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

JavaScript에서 객체 배열을 연도별로 그룹화하는 방법

문제 상황

다음과 같이 연도(year)와 주(week) 정보를 담고 있는 객체 배열이 있다고 가정해 보겠습니다.

const arr = [
    {year: 2017, week: 45},
    {year: 2017, week: 46},
    {year: 2017, week: 47},
    {year: 2017, week: 48},
    {year: 2017, week: 50},
    {year: 2017, week: 52},
    {year: 2018, week: 1},
    {year: 2018, week: 2},
    {year: 2018, week: 5}
];

여기서 요구되는 것은 이러한 배열을 입력으로 받아, "year" 속성의 값이 서로 같은 객체들을 하나의 객체로 묶어 새로운 배열을 반환하는 JavaScript 함수를 작성하는 것입니다.

따라서 위 배열에 대한 출력 결과는 대략 다음과 같은 구조가 됩니다.

[
    {
        "2017": [
            { week: 45 },
            { week: 46 },
            { week: 47 },
            { week: 48 },
            { week: 50 },
            { week: 52 }
        ]
    },
    {
        "2018": [
            { week: 1 },
            { week: 2 },
            { week: 5 }
        ]
    }
]

해결 코드

이 문제는 forEach 반복문과 참조용 맵(map) 객체를 활용해 해결할 수 있습니다.

const arr = [
    {year: 2017, week: 45},
    {year: 2017, week: 46},
    {year: 2017, week: 47},
    {year: 2017, week: 48},
    {year: 2017, week: 50},
    {year: 2017, week: 52},
    {year: 2018, week: 1},
    {year: 2018, week: 2},
    {year: 2018, week: 5}
];

const groupByYear = arr => {
    const res = [];
    const map = {};
    arr.forEach(item => {
        const temp = {};
        if (!map[item.year]) {
            map[item.year] = [];
            temp[item.year] = map[item.year];
            res.push(temp);
        };
        map[item.year].push({ value: item.week });
    });
    return res;
};

console.log(JSON.stringify(groupByYear(arr), undefined, 4));

코드 동작 원리

  • res: 최종 결과를 담을 배열입니다.
  • map: 각 연도를 키로 하여, 해당 연도의 주(week) 목록 배열을 저장하는 참조용 객체입니다.
  • 배열을 순회하는 도중 특정 연도가 처음 등장하면 새로운 배열을 생성하고, 이 배열을 담은 임시 객체(temp)를 결과 배열(res)에 추가합니다.
  • 이후 같은 연도의 항목들은 map에 저장된 동일한 배열 객체에 계속 push되므로, 결과 배열 안의 객체에도 자동으로 함께 반영됩니다. 이는 JavaScript의 참조(reference) 공유 특성을 활용한 방식입니다.

실행 결과

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

[
    {
        "2017": [
            { "value": 45 },
            { "value": 46 },
            { "value": 47 },
            { "value": 48 },
            { "value": 50 },
            { "value": 52 }
        ]
    },
    {
        "2018": [
            { "value": 1 },
            { "value": 2 },
            { "value": 5 }
        ]
    }
]

참고: 최신 문법(Object.groupBy) 활용하기

ES2024에 정식 도입된 Object.groupBy() 메서드를 사용하면 위 로직을 한 줄로 대체할 수 있습니다.

const grouped = Object.groupBy(arr, item => item.year);
console.log(grouped);
// { 2017: [{...}, {...}], 2018: [{...}] }

반환값은 배열이 아닌 일반 객체라는 점만 유의하면 되며, 지원 환경에 따라 폴리필(polyfill)이 필요할 수 있습니다. 구버전 브라우저 호환성이 중요하다면 앞서 소개한 reduce 또는 forEach 기반 구현을 사용하는 것이 안전합니다.