안녕하세요

우테코 프리코스 1주차 - 문제 6 (리팩토링O) 본문

우테코 프리코스/1주차

우테코 프리코스 1주차 - 문제 6 (리팩토링O)

sakuraop 2022. 11. 1. 01:25

 

https://github.com/youngentry/javascript-onboarding/blob/youngentry/docs/PROBLEM6.md

 

🚀 기능 요구 사항

우아한테크코스에서는 교육생(이하 크루) 간 소통 시 닉네임을 사용한다. 간혹 비슷한 닉네임을 정하는 경우가 있는데, 이러할 경우 소통할 때 혼란을 불러일으킬 수 있다.

혼란을 막기 위해 크루들의 닉네임 중 같은 글자가 연속적으로 포함 될 경우 해당 닉네임 사용을 제한하려 한다. 이를 위해 같은 글자가 연속적으로 포함되는 닉네임을 신청한 크루들에게 알려주는 시스템을 만들려고 한다.

신청받은 닉네임 중 같은 글자가 연속적으로 포함 되는 닉네임을 작성한 지원자의 이메일 목록을 return 하도록 solution 메서드를 완성하라.

제한사항

  • 두 글자 이상의 문자가 연속적으로 순서에 맞추어 포함되어 있는 경우 중복으로 간주한다.
  • 크루는 1명 이상 10,000명 이하이다.
  • 이메일은 이메일 형식에 부합하며, 전체 길이는 11자 이상 20자 미만이다.
  • 신청할 수 있는 이메일은 email.com 도메인으로만 제한한다.
  • 닉네임은 한글만 가능하고 전체 길이는 1자 이상 20자 미만이다.
  • result는 이메일에 해당하는 부분의 문자열을 오름차순으로 정렬하고 중복은 제거한다.

실행 결과 예시

formsresult

[ ["jm@email.com", "제이엠"], ["jason@email.com", "제이슨"], ["woniee@email.com", "워니"], ["mj@email.com", "엠제이"], ["nowm@email.com", "이제엠"] ] ["jason@email.com", "jm@email.com", "mj@email.com"]

 


 

✔구현 기능 목록 리스트

  • 1단계) 모든 연속되는 패턴을 찾아 Set 집함에 담아 중복을 없앱니다.
  • 2단계) [pattern, 0] 배열을 생성하여 패턴이 나타나는 횟수를 저장합니다.
  • 3단계) count를 하기 위해 우선 모든 닉네임에 대해 포함된 패턴을 확인합니다.
  • 4단계) 패턴이 포함된 횟수를 각각 카운트합니다.
  • 5단계) 중복패턴만을 담은 배열을 생성합니다.
  • 6단계) 중복패턴을 포함하는 아이디만을 담은 배열 생성
  • 7단계) 중복을 제거하고 오름차순으로 정렬한 배열을 반환합니다.

 

아쉬운 점

  • 로직을 잘 생각하면 단계를 줄이거나
  • 중복되는 이중 for문의 사용을 두 번으로 줄일 수 있을 것 같습니다.

 


 
 
function problem6(forms) {
    let nicknameSet = new Set([]);
    // 1단계) 모든 연속되는 패턴을 찾아 집합으로 만들기 ===> ex) ["제이", "이엠", ~]
    for (let i = 0; i < forms.length; i++) {
        let nickname = forms[i][1];
        for (let j = 0; j < nickname.length - 1; j++) {
            nicknameSet.add(nickname[j] + nickname[j + 1]);
        }
    }

    // 2단계) 패턴이 몇 번 나타나는지 count 하기위해 [pattern, 0] 배열을 생성
    const patternArray = [...nicknameSet];
    for (let i = 0; i < patternArray.length; i++) {
        patternArray[i] = [patternArray[i], 0];
    }

    const includedPatternArray = [];
    // 3단계) count를 하기 위해 모든 닉네임에 대해 포함된 패턴을 확인
    for (let i = 0; i < forms.length; i++) {
        for (let k = 0; k < patternArray.length; k++) {
            let pattern = patternArray[k][0];
            if (forms[i][1].includes(pattern)) {
                includedPatternArray.push([forms[i][0], pattern]);
            }
        }
    }

    // 4단계) 패턴이 포함된 횟수를 각각 카운트 ===> ex) [pattern1, 0], [pattern2, 2], [pattern3, 3]
    for (let i = 0; i < patternArray.length; i++) {
        for (let k = 0; k < includedPatternArray.length; k++) {
            if (patternArray[i][0].includes(includedPatternArray[k][1])) {
                patternArray[i][1] += 1;
            }
        }
    }

    // 5단계) 중복패턴만을 담은 배열 생성 => [pattern, 2이상]
    const repetitionArray = patternArray.filter((el) => el[1] >= 2);

    // 6단계) 중복패턴을 포함하는 아이디만을 담은 배열 생성 ===> ex) ["jm@email.com", "jason@email.com", ~]
    const resultIdArray = [];
    for (let i = 0; i < includedPatternArray.length; i++) {
        for (let j = 0; j < repetitionArray.length; j++) {
            if (includedPatternArray[i][1].includes(repetitionArray[j][0])) {
                resultIdArray.push(includedPatternArray[i][0]);
            }
        }
    }

    // 7단계) 중복을 제거하고 오름차순으로 정렬한 배열을 반환
    const result = new Set([...resultIdArray]);
    return [...result].sort();
}

module.exports = problem6;

리팩토링 전 코드

function problem6(forms) {
    let nicknameSet = new Set([]);
    for (let i = 0; i < forms.length; i++) {
        let nickname = forms[i][1];
        for (let j = 0; j < nickname.length - 1; j++) {
            nicknameSet.add(nickname[j] + nickname[j + 1]);
        }
    }

    const patternArray = [...nicknameSet];
    for (let i = 0; i < patternArray.length; i++) {
        patternArray[i] = [patternArray[i], 0];
    }

    const includedPatternArray = [];
    for (let i = 0; i < forms.length; i++) {
        for (let k = 0; k < patternArray.length; k++) {
            let pattern = patternArray[k][0];
            if (forms[i][1].includes(pattern)) {
                includedPatternArray.push([forms[i][0], pattern]);
            }
        }
    }

    for (let i = 0; i < patternArray.length; i++) {
        for (let k = 0; k < includedPatternArray.length; k++) {
            if (patternArray[i][0].includes(includedPatternArray[k][1])) {
                patternArray[i][1] += 1;
            }
        }
    }

    const repetitionArray = patternArray.filter((el) => el[1] >= 2);

    const resultIdArray = [];
    for (let i = 0; i < includedPatternArray.length; i++) {
        for (let j = 0; j < repetitionArray.length; j++) {
            if (includedPatternArray[i][1].includes(repetitionArray[j][0])) {
                resultIdArray.push(includedPatternArray[i][0]);
            }
        }
    }

    const result = new Set([...resultIdArray]);
    return [...result].sort();
}

module.exports = problem6;

리팩토링 후 코드

  • Set 객체 대신 Object를 활용하여 코드마다 중복되던 역할들을 간소화
function problem6(forms) {
    const nicknameObject = {};
    for (let i = 0; i < forms.length; i++) {
        for (let j = 0; j < forms[i][1].length - 1; j++) {
            let pattern = forms[i][1][j] + forms[i][1][j + 1];
            nicknameObject[pattern] = 0;
        }
    }
    const nicknameArray = Object.keys(nicknameObject);
    for (let i = 0; i < forms.length; i++) {
        for (let j = 0; j < nicknameArray.length; j++) {
            if (forms[i][1].includes(nicknameArray[j])) {
                nicknameObject[nicknameArray[j]] += 1;
            }
        }
    }

    const countArray = Object.entries(nicknameObject);
    const duplicationArray = countArray.filter((el) => el[1] > 1);

    const resultArray = [];
    for (let i = 0; i < forms.length; i++) {
        for (let j = 0; j < duplicationArray.length; j++) {
            if (forms[i][1].includes(duplicationArray[j][0])) {
                resultArray.push(forms[i][0]);
            }
        }
    }

    const orderedResult = new Set([...resultArray]);
    const removedArray = [...orderedResult].sort();
    return removedArray;
}

module.exports = problem6;