// 클린코드의 규칙에 따라 부정조건문을 쓰지 않고,
// 조건문을 캡슐화하기 위해 따로 뺀 함수이다.
const shouldInitProp = (obj, prop) => {
return !obj.hasOwnProperty(prop);
};
const convertToHash = (arr) => {
const hashTable = {};
for (let item of arr) {
// 클린코드에서 조건문은 최대한 쓰지 말라고 했고,
// 조건문을 쓸 경우에는 캡슐화를 하라고 했다.
// 여기서 조건문을 어떻게 뺄 수 있을까...
if (shouldInitProp(hashTable, item)) {
hashTable[item] = 1;
} else {
hashTable[item]++;
}
}
return hashTable;
};
const solution = (participant, completion) => {
const hashOfParticipant = convertToHash(participant);
for (const name of completion) {
hashOfParticipant[name]--;
// 값이 1인 프로퍼티를 다시 순회하면서 찾지 않기 위해
// 값이 0이 된 프로퍼티는 즉시 삭제
if (hashOfParticipant[name] == 0) {
delete hashOfParticipant[name];
}
}
// 마지막에는 객체에 프로퍼티가 하나만 남아있을 것이므로
// 그대로 반환
return Object.keys(hashOfParticipant)[0];
};
다른 사람의 풀이 중에 내 풀이보다 효율성이 높은 풀이가 하나 있었는데 내 convertToHash함수를 reduce함수 한 줄로 대체해버린 코드였다.
(그놈의 reduce)
그런데 클린 코드에서 삼항 연산자에 대한 언급이 없는데, 이 역시 조건문이니 최대한 지양해야 하는 걸까
개선할 점을 고려한 결과 수정한 코드는 다음과 같다.
// 클린코드의 규칙에 따라 부정조건문을 쓰지 않고,
// 조건문을 캡슐화하기 위해 따로 뺀 함수이다.
const shouldInitProp = (obj, prop) => {
return !obj.hasOwnProperty(prop);
};
// reducer함수이다.
// 초기 값으로 {}(객체 리터럴)을 전달하기 때문에
// 맨 처음 받게 되는 인자는 hash:{}, item:배열의 첫 번째 원소이다.
const convertToHash = (hash, item) => {
if (shouldInitProp(hash, item)) {
hash[item] = 1;
} else {
hash[item]++;
}
return hash;
};
const getAnswer = (name, obj) => {
// participant에 있는데 completion에 없다면 반환
// completion에 프로퍼티로 있지만 그 값이 0인 경우에도 반환
// (동명이인으로써 이미 --연산자를 거쳤다는 것이므로)
if (obj[name]) {
obj[name]--;
} else {
return true;
}
};
const solution = (participant, completion) => {
const hashOfCompletion = completion.reduce(convertToHash, {});
return participant.find((name) => getAnswer(name, hashOfCompletion));
};
일단 기존의 내 코드는 participant를 해쉬로 만들고 completion을 순회하면서 해쉬의 값을 차감하였다.
그 결과 남은 프로퍼티(값이 1인)를 반환하고자 한 것이다.
그런데 이렇게 하면 결국 completion을 전부 순회해야만 했다.
기준을 바꿔 completion을 해쉬로 만들고 participant로 순회를 돌면, 해쉬에 값이 없거나 값이 0인(동명이인으로 이미 차감된) 프로퍼티를 찾는 순간 순회를 끝까지 돌 필요가 없다.
그리고 reduce와 find등의 메소드를 쓰는 함수형 프로그래밍이 클린 코드의 관점에서도 더욱 바람직하다고 한다.
function solution(participant, completion) {
const hash = {};
for (const name of completion) {
if (!hash.hasOwnProperty(name)) {
hash[name] = 1;
} else {
hash[name]++;
}
}
for (const name of participant) {
if (!hash.hasOwnProperty(name)) {
return name;
}
hash[name]--;
if (hash[name] == 0) {
delete hash[name];
}
}
}