Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript에서 중복 배열 값을 합쳐 고유한 배열 만들기

문제 상황

JavaScript를 다루다 보면 중첩 배열(배열의 배열)에서 첫 번째 요소가 중복되는 하위 배열을 하나로 합치고, 특정 숫자 값을 누적해야 하는 경우가 종종 있습니다.

예를 들어 다음과 같은 배열이 있다고 가정해 보겠습니다.

const arr = [[12345, "product", "10"],[12345, "product", "15"],[1234567, "other", "10"]];

모든 하위 배열은 정확히 세 개의 요소, 즉 ID, 이름, 수량을 가지고 있습니다. 여기서 우리가 작성해야 할 함수는 다음과 같은 동작을 수행해야 합니다.

  • 첫 번째 요소(ID)가 중복되는 하위 배열은 하나만 남기고 제거합니다.
  • 제거된 하위 배열의 세 번째 요소(수량)는 남아 있는 동일한 ID의 하위 배열에 더해 누적합니다.

따라서 위 배열의 최종 결과물은 다음과 같아야 합니다.

const output = [[12345, "product", "25"],[1234567, "other", "10"]];

ID가 12345인 두 개의 하위 배열이 하나로 병합되면서 수량 1015가 더해져 25가 된 것을 확인할 수 있습니다.

해결 방법: 객체 맵을 활용한 접근

이 문제는 각 ID의 결과 배열 내 위치(index)를 기록하는 객체(맵)를 활용하면 효율적으로 해결할 수 있습니다. 배열을 한 번만 순회하면 되므로 시간 복잡도는 O(n)입니다.

const arr = [[12345, "product", "10"],[12345, "product", "15"],[1234567, "other", "10"]];

const addSimilar = (arr = []) => {
    const res = [];
    const map = {};
    arr.forEach(el => {
        const [id, name, amount] = el;
        if(map.hasOwnProperty(id)){
            // 이미 존재하는 ID라면 수량을 누적
            const newAmount = +amount + +res[map[id] - 1][2];
            res[map[id] - 1][2] = '' + newAmount;
        }else{
            // 처음 보는 ID라면 결과 배열에 추가하고 위치 기록
            map[id] = res.push(el);
        }
    });
    return res;
}

console.log(addSimilar(arr));

코드 동작 원리

  1. 구조 분해 할당: 각 하위 배열에서 id, name, amount를 추출합니다.
  2. 중복 확인: map.hasOwnProperty(id)로 해당 ID가 이미 처리되었는지 검사합니다.
  3. 수량 누적: 중복된 ID라면 단항 더하기 연산자(+)로 문자열 수량을 숫자로 변환한 뒤 더하고, 다시 문자열로 변환하여 저장합니다.
  4. 신규 등록: 처음 등장한 ID라면 res.push(el)로 결과 배열에 추가하고, 반환값(새로운 배열 길이)을 맵에 저장합니다. 이때 인덱스보다 1 큰 값이 저장되므로 조회 시 -1로 보정합니다.

실행 결과

콘솔에 출력되는 결과는 다음과 같습니다.

[ [ 12345, 'product', '25' ], [ 1234567, 'other', '10' ] ]

마무리

이 방식은 데이터 집계, 장바구니 항목 병합, 로그 정리 등 실무에서 자주 마주치는 패턴입니다. reduce() 메서드나 Map 객체를 사용하는 변형도 가능하니, 상황에 맞게 응용해 보시기 바랍니다.