배열을 입력받아 모든 중복 값을 제거하고, 제거된 개수만큼 빈 문자열('')을 배열 끝에 추가하는 함수를 작성해 보겠습니다.
예를 들어 어떤 값이 여러 번 반복되어 있다면, 첫 번째 등장만 남기고 나머지 중복은 모두 제거한 뒤 그만큼의 빈 문자열을 배열 맨 뒤에 채워 넣으면 됩니다.
접근 방법
이 문제는 Array.prototype.reduce() 메서드를 활용하면 배열을 한 번만 순회하면서 해결할 수 있습니다. 핵심 아이디어는 다음과 같습니다.
- 각 요소에 대해
lastIndexOf()를 사용해 해당 값이 마지막으로 등장하는 위치인지 확인합니다. - 현재 인덱스가 마지막 등장 위치와 일치하면 고유 값이므로 결과 배열(
res)에 그대로 담고, 일치하지 않으면 뒤에 같은 값이 더 있다는 뜻이므로 중복 카운트(count)를 1 증가시킵니다. - 순회가 끝나면 고유 값 배열 뒤에 빈 문자열을
count개 이어 붙여 최종 배열을 반환합니다.
구현 코드
const arr = [1, 2, 3, 1, 2, 3, 2, 2, 3, 4, 5, 5, 12, 1, 23, 4, 1];
const deleteAndInsert = arr => {
const creds = arr.reduce((acc, val, ind, array) => {
let { count, res } = acc;
// 현재 위치가 해당 값의 마지막 등장 지점이라면 고유 값으로 판단
if (array.lastIndexOf(val) === ind) {
res.push(val);
} else {
count++; // 중복 발견 시 카운트 증가
}
return { res, count };
}, { count: 0, res: [] });
const { res, count } = creds;
// 제거된 중복 개수만큼 빈 문자열을 배열 끝에 추가
return res.concat(Array(count).fill(""));
};
console.log(deleteAndInsert(arr));
참고:
" ".repeat(count).split(" ")방식으로도 빈 문자열 배열을 만들 수 있지만, 이 방법은 문자열을 분리하는 과정에서 빈 문자열이 하나 더 생기는 사소한 오차가 있습니다.Array(count).fill("")을 사용하면 정확히count개의 빈 문자열을 얻을 수 있어 더 안전합니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같이 출력됩니다. 원래 배열의 길이(17)가 그대로 유지되면서, 중복이 제거된 자리만큼 빈 문자열로 채워진 것을 확인할 수 있습니다.
[ 2, 3, 5, 12, 23, 4, 1, '', '', '', '', '', '', '', '', '', '' ]
동작 원리 정리
- 누적 객체 초기화:
reduce()의 초기값으로{ count: 0, res: [] }를 설정해 중복 개수와 결과 배열을 동시에 관리합니다. - lastIndexOf 비교: 현재 인덱스와 해당 값의 마지막 인덱스가 같다는 것은 이후에 동일한 값이 없다는 의미이며, 이 경우에만 결과 배열에 값을 유지합니다.
- 빈 문자열 채우기:
Array(count).fill("")로 길이가count인 배열을 만들어 모든 요소를 빈 문자열로 채운 뒤,concat()으로 기존 배열과 합칩니다.
대안: Set을 활용한 간결한 방법
중복 개수는 '전체 길이 − 고유 값 개수'로도 구할 수 있습니다. Set을 활용하면 코드를 훨씬 간결하게 작성할 수 있습니다.
const deleteAndInsert = arr => {
const unique = [...new Set(arr)];
const dupCount = arr.length - unique.length;
return unique.concat(Array(dupCount).fill(""));
};
이 방식은 각 값의 첫 등장 순서를 그대로 유지하면서 중복을 제거하므로, 가독성과 성능 면에서 모두 유리합니다.