취업/코딩 테스트

[프로그래머스] 2023 KAKAO BLIND RECRUITMENT > 개인정보 수집 유효기간 (javascript)

dhsimpson 2023. 1. 7. 19:43

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/150370

 

프로그래머스의 개인정보 수집 유효기간 문제이다.

 

 

문제

[오늘 날짜] [개인정보 수집 약관 종류] [등록된 사용자별 개인정보 수집약관 리스트] 를 input 으로 받고

[유효기간 만기 된 수집약관 리스트] 를 return 하는 문제이다.

 

문제 원본을 보려면 아래를 펼쳐 보자.

 

 

 


풀이

1. createTermsMap(terms) 메서드로 이용약관 종류를 정리한 key-value Map을 만든다.

function createTermsMap(terms) {
    return terms.reduce((acc, curr)=> {
        const [termName, term] = curr.split(' ')
        acc.set(termName, Number(term));
        return acc;
    } ,new Map());
}

2. 각 이용약관 마다 '유효기간 만료' 여부를 판단하는 loop 를 시행한다.

유효기간이 지난 이용약관은 answer.push(idx+1) 해 준다.

1. createDateAndAddTerm 메서드는 이용약관 등록날짜 에서 유효기간을 더해 해당 약관의 만료일을 [cYear, cMonth, cDate] 로 리턴한다.
2. proccessYear 메서드는 유효기간이 '이번년도' 보다 지났다면 answer.push 해 주고, '다음년도' 이후라면 다음 루프를 돌도록 한다.
3. proccessMonth 메서드는 2. 의 로직을 'Month' 에 적용한다.
4. proccessDate 메서드는 2. 의 로직을 'Date' 에 적용한다.

(c.f. 각 메서드 내용은 아래의 전체코드 보기에서 볼 수 있다.)

privacies.forEach((priv, idx) => {
    let [collectedDate, term] = priv.split(' ');

    let [cYear, cMonth, cDate] = createDateAndAddTerm(collectedDate, termsMap, term);

    if(proccessYear(answer, year, cYear, idx)){
        return;
    }

    //연도는 같은 경우
    if(proccessMonth(answer, month, cMonth, idx)){
        return;
    }

    //달 이 같은 경우
    proccessDate(answer, date, cDate, idx);
})

 

 


예외상황

 

1. javascript 에서의 나눗셈.

cMonth  + 유효기간 이 12 를 초과할 경우, 12로 나눈 몫 만큼 cYear 에 더해줘야 한다.

그런데, javascript 의 Number 는 기본적으로 부동소숫점(float, double) 이므로 나눈 몫이 '소수'일 수가 있다.

그러므로 꼭 Math.floor 를 이용해 소숫점 아래는 버림해 몫을 정수로 만들어 주자.

(이것 때문에 제출 시 30% 이상 통과하지 못했다... 원인을 못 찾아 한참을 해맸다)

 

2. cMonth + 유효기간이 12의 배수일 때

cMonth + 유효기간 이 12 를 초과할 경우, 12로 나눈 몫 만큼 cYear 에 더해주고, 나머지를 cMonth 로 할당해준다.

그치만, 12의 배수인 경우(24, 36 ....) 12로 나눈 나머지가 0이 돼 cMonth 에 0을 할당해주게 된다.

이 경우엔 ( 몫 - 1 ) 을 해주고, cMonth 에 12를 할당해 주자.

 


전체 코드

function solution(today, terms, privacies) {
    var answer = [];
    const [year, month, date] = createDate(today);
    const termsMap = createTermsMap(terms);
    
    privacies.forEach((priv, idx) => {
        let [collectedDate, term] = priv.split(' ');
        
        let [cYear, cMonth, cDate] = createDateAndAddTerm(collectedDate, termsMap, term);
        
        if(proccessYear(answer, year, cYear, idx)){
            return;
        }
        
        //연도는 같은 경우
        if(proccessMonth(answer, month, cMonth, idx)){
            return;
        }
        
        //달 이 같은 경우
        proccessDate(answer, date, cDate, idx);
    })
    
    return answer;
}

function createDate(today) {
    const [year, month, date] = today.split('.');
    return [Number(year), Number(month), Number(date)];
}

function createTermsMap(terms) {
    return terms.reduce((acc, curr)=> {
        const [termName, term] = curr.split(' ')
        acc.set(termName, Number(term));
        return acc;
    } ,new Map());
}

function createDateAndAddTerm(collectedDate, termsMap, term) {
    let [cYear, cMonth, cDate] = createDate(collectedDate);

    cMonth += termsMap.get(term);

    if(cMonth > 12) {
        const quot = Math.floor(cMonth / 12);
        const division = cMonth % 12;

        if(division == 0){
            cMonth = 12;
            cYear += (quot-1);
        }else {
            cMonth = division;
            cYear += quot;
        }
    }
    return [cYear, cMonth, cDate];
}

function proccessYear(answer, year, cYear, idx) {
    if(year > cYear) {
        answer.push(idx+1);
        return true;
    }else if(year < cYear) {
        return true;
    }
    return false;
}

function proccessMonth(answer, month, cMonth, idx) {
    if(month > cMonth) {
        answer.push(idx+1);
        return true;
    }else if(month < cMonth){
        return true;
    }
    return false;
}

function proccessDate(answer, date, cDate, idx) {
    if(date >= cDate) {
        answer.push(idx+1);
    }
}