deleteNth
Codewars 문제 풀이
deleteNth 문제
목록 arr와 숫자 N이 주어지면 순서를 변경하지 않고 최대 N번까지 각 arr 수를 포함하는 새 배열을 만듭니다. 예를 들어, N = 2이고 입력이 [1,2,1,1,2,3]인 경우, 반복횟수가 최대 2번이기 때문에 [1,2,1,2,3]이 됩니다.
예시
console.log(deleteNth([1, 1, 1, 1], 2)); // return [1,1]
console.log(deleteNth([20, 37, 20, 21], 1)); // return [20,37,21]
나의 풀이
function deleteNth(arr, n) {
const result = [];
const countNum = {};
arr.forEach((num) => {
countNum[num] ? countNum[num]++ : (countNum[num] = 1);
if (countNum[num] <= n) result.push(num);
});
return result;
}
- 조건에 따라 원본 배열에서 허용되는 중복 횟수의 숫자만 추출해 새 배열을 만들어야 하므로
result
변수를 선언하고 빈 배열을 할당한다. - 요소의 중복 횟수를 세기 위해
countNum
변수를 생성하고 빈 객체를 할당한다.
(빈 객체를 생성한 이유는 주어진 요소들을 프로퍼티 키로 지정하고 각 요소의 반복 횟수를 프로퍼티 값으로 정리하기 위함이다.) - 매핑을 통해 새로운 배열을 바로 반환하는 목적이 아닌 주어진 배열을 순회하면서 조건에 맞는 값을 찾아
result
에push
하기 위한 목적이므로map()
이 아닌forEach()
메서드를 사용했다. - 삼항연산자를 이용해 만약
countNum
객체에 중복되는num
있다면+1
을 통해 카운트시키고 없다면1
로 카운트를 시작한다. - 카운트가 끝나면 바로 다시 순회시키지 않고
if
문을 사용한다. 만약 해당 숫자의 카운트가 최대횟수n
을 넘지 않는다면 중복을 허용하기 때문에result
배열에 숫자num
을push()
한다. 만약 최대횟수를 넘어버리면 조건이 불충족되므로push
를 하지 않는다.(push()
메서드는 뒤에서부터 요소를 넣기 때문에 원본배열의 순서 그대로 유지할 수 있다.) - 모든 순회가 끝나면
result
값을 반환한다.
만약 새로운 배열의 요소 값이 기존의 순서가 아닌 오름차순으로 반환해야 한다면 마지막 코드 줄만 수정하면 된다!
return result.sort((a,b) => a-b);
다른 사람 풀이
Balkoth (plus 159 more warriors)
function deleteNth(arr,x) {
var cache = {};
return arr.filter(function(n) {
cache[n] = (cache[n]||0) + 1;
return cache[n] <= x;
});
}
- 반복되는 요소의 수를 세기 위해
cache
변수를 생성하고 빈 객체를 할당한다. - 전달받은
arr
을filter()
메서드를 이용해 조건에 맞는 요소만 반환시킨다. cache
객체의 프로퍼티 생성과 중복 횟수 카운트는 논리합 단축 평가 방식을 사용했다.
cache
객체 내filter()
메서드에서 순회하는 숫자가 프로퍼티로 있다면cache[n]||0
는 기존cache[n]
값에+1
증가한다. 하지만 없다면(undefined || 0)
으로 값은0
으로 할당되고+1
증가한다.
(객체에 존재하지 않는 프로퍼티에 접근하면 ReferenceError가 발생하지 않고 undefined를 반환한다.)cache[n]
즉, 해당 숫자의 중복 카운트가x
보다 작거나 같으면true
이므로 반환할 새 배열에 저장하고 만약 중복 횟수가 넘어버리면false
로 저장하지 않는다.
위 풀이를 보고 든 생각
1. 조건에 따라 걸러내는 작업이 필요하기 때문에filter()
메서드를 떠올렸지만filter()
메서드를 사용하면 카운트 정보를 담은 객체에 대한if
문을 못사용한다는 생각을 했었다. 하지만filter()
메서드에 핵심은 조건에 맞는 요소를 뽑아 새 배열을 만들 수 있다는 점이다.if
문을 작성하려 하기 보다filter
의 콜백함수에 조건을 작성할 생각을 하자!
2. 객체 프로퍼티 생성에 무조건 삼항 연산자만 생각했는데 논리 단축 평가를 사용해 값을 할당할 수 있다는 것을 배웠다. 논리합, 논리곱으로if
문을 대체할 수 있고if...else
문은 삼항연산자로 대체할 수 있다고 공부해도 역시 실제로 문제를 풀어야 깨닫고 기억할 수 있다. 개념을 눈으로만 보고 그것에 대해 안다고 절!대! 생각하지 말자!!
jhoffner
function deleteNth(arr,x){
var count = {};
return arr.filter(function(a){
count[a] = ~~count[a]+1;
return count[a]<=x;
})
}
위 방법과 거의 흡사하지만 count[a] = ~~count[a]+1
이 다르다.
~
는 무엇인가?
~
은 비트 NOT 연산자다. 피연산자의 비트를 반전한다. 피연산자가 숫자가 아닌 경우 32비트 부호 있는 정수로 변환한다.~0; // -1 ~-1; // 0 ~1; // -2
count
객체에a
프로퍼티키가 없다면 값은undefined
다.undefined
는 연산자에 의해0
값으로 변환과 동시에 비트 NOT이 적용되어 값-1
이 된다. 여기서~
이 한 번 더 적용되어-1
의 비트 반전인0
값을 가지게 된다. 뒤이은+1
로 카운트가 시작된다.count
객체에a
프로퍼티키가 있다면 값은 기존의 값 그대로다. 왜냐하면~
이 2번 적용되면서 비트 NOT의 비트 NOT 즉, 원래값으로 다시 돌아온다.
따라서 만약 undefined
를 숫자 0
으로 변환하고 싶다면 ~~
연산자를 사용하면 좋을 것 같다.
연산자에서 숫자가 아닌
+undefined
,-undefined
는 값이0
이 아닌NaN
이다.
논리연산자에서 부울이 아닌falsy
값을 가진undefined
는false
로 고려된다.
비트연산자에서 숫자가 아닌undefined
는 32비트 정수로 변환되어 값이0
이다.
Author And Source
이 문제에 관하여(deleteNth), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sozero/deleteNth저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)