JavaScript를 사용하다 보면 배열에 담긴 값들 중 중복을 제거한 고유(distinct) 요소만 골라 합계를 구해야 하는 경우가 종종 있습니다. 이번 글에서는 그러한 배열을 입력받아 고유 요소들의 합을 반환하는 함수를 작성하는 방법을 알아보겠습니다.
문제 정의
예를 들어 다음과 같은 숫자 배열이 있다고 가정해 보겠습니다.
const arr = [1, 5, 2, 1, 2, 3, 4, 5, 7, 8, 7, 1];
이 배열에는 1, 2, 5, 7처럼 여러 번 반복되는 값들이 포함되어 있습니다. 우리가 만들 함수는 이 배열을 인자로 받아, 각 고유 값을 한 번씩만 더한 결과를 반환해야 합니다.
위 배열의 경우 고유 요소는 1, 5, 2, 3, 4, 7, 8이며, 이들의 합은 다음과 같습니다.
30
구현 방법: lastIndexOf() 활용하기
가장 직관적인 접근 방식은 각 요소에 대해 lastIndexOf() 메서드를 활용하는 것입니다. 어떤 요소의 현재 인덱스와 해당 값의 마지막 등장 인덱스가 일치한다면, 그 값은 더 이상 뒤에서 반복되지 않는다는 의미이므로 합계에 한 번만 포함시키면 됩니다.
코드 예제
const arr = [1, 5, 2, 1, 2, 3, 4, 5, 7, 8, 7, 1];
const distinctSum = arr => {
let res = 0;
for(let i = 0; i < arr.length; i++){
// 현재 인덱스가 해당 값이 마지막으로 등장하는 위치라면
if(i === arr.lastIndexOf(arr[i])){
res += arr[i];
};
continue;
};
return res;
};
console.log(distinctSum(arr));실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 출력이 나타납니다.
30
동작 원리 살펴보기
이 코드의 핵심 로직은 다음과 같습니다.
- 배열을 처음부터 끝까지 순회하면서 각 요소를 확인합니다.
arr.lastIndexOf(arr[i])는 현재 값이 배열 안에서 마지막으로 등장하는 인덱스를 반환합니다.- 현재 인덱스
i가 그 마지막 인덱스와 같다면, 같은 값이 뒤에 더 이상 존재하지 않으므로 해당 값을 합계에 더합니다. - 반대로 중복된 값이라면 조건을 통과하지 못해 자동으로 건너뛰게 됩니다.
참고: Set을 활용한 대안
ES6의 Set 객체를 사용하면 코드를 더욱 간결하게 작성할 수도 있습니다.
const distinctSum = arr => {
const unique = [...new Set(arr)];
return unique.reduce((sum, num) => sum + num, 0);
};
console.log(distinctSum([1, 5, 2, 1, 2, 3, 4, 5, 7, 8, 7, 1])); // 30Set은 중복 값을 허용하지 않기 때문에 배열을 Set으로 변환하면 자동으로 중복이 제거됩니다. 이후 reduce()로 합계를 계산하면 됩니다. 단, lastIndexOf() 방식은 시간 복잡도가 O(n²)인 반면, Set 방식은 O(n)으로 더 효율적이므로 배열 크기가 클 때는 Set 활용을 권장합니다.