자동차 정보를 담고 있는 다음과 같은 객체 배열이 있다고 가정해 보겠습니다. 각 객체는 group(소속 그룹 목록), name(브랜드명), code(식별 코드) 세 가지 속성을 가지고 있습니다.
const arr = [
{
"group":[],
"name": "All Makes",
"code": ""
},
{
"group":["Group A"],
"name": "BMW",
"code": "X821"
},
{
"group":["Group B"],
"name": "Audi",
"code": "B216"
},
{
"group":["Group B"],
"name": "Ford",
"code": "P385"
},
{
"group":["Group B", "Group C"],
"name": "Mercedes",
"code": "H801"
},
{
"group":["Group C"],
"name": "Honda",
"code": "C213"
}
];문제 정의
우리는 이러한 객체 배열을 입력으로 받는 JavaScript 함수를 작성해야 합니다. 이 함수는 각 객체의 group 속성을 기준으로 배열 내 객체들을 그룹별로 묶어야 하며, 다음 조건을 충족해야 합니다.
- 같은 그룹에 속한 객체들은 하나의 배열로 묶입니다.
- group 속성에 두 개 이상의 요소가 포함된 객체(예: Mercedes)는 해당하는 모든 그룹에 중복해서 나타나야 합니다.
- group 속성이 빈 배열인 객체(예: All Makes)는 어떤 그룹에도 포함되지 않습니다.
따라서 위 배열에 대한 최종 출력 결과는 다음과 같은 형태가 되어야 합니다.
const output = [
{
"group": "Group A",
"cars": [
{
name: "BMW",
code: "X821"
}
]
},
{
"group": "Group B",
"cars": [
{
name: "Audi",
code: "B216"
},
{
name: "Ford",
code: "P385"
},
{
name: "Mercedes",
code: "H801"
}
]
},
{
"group": "Group C",
"cars": [
{
name: "Mercedes",
code: "H801"
},
{
name: "Honda",
code: "C213"
}
]
}
];예제 코드
이 문제는 reduce()와 Object.entries()를 조합하면 간결하게 해결할 수 있습니다. 먼저 reduce로 그룹 이름을 키로 하는 객체를 만들고, 이후 Object.entries로 키-값 쌍 배열로 변환한 뒤 map으로 원하는 출력 형태를 만듭니다.
const arr = [
{
"group":[],
"name": "All Makes",
"code": ""
},
{
"group":["Group A"],
"name": "BMW",
"code": "X821"
},
{
"group":["Group B"],
"name": "Audi",
"code": "B216"
},
{
"group":["Group B"],
"name": "Ford",
"code": "P385"
},
{
"group":["Group B", "Group C"],
"name": "Mercedes",
"code": "H801"
},
{
"group":["Group C"],
"name": "Honda",
"code": "C213"
}
];
const groupTogether = (arr = []) => {
let res = []
res = Object.entries(arr.reduce((acc, { group, ...r }) => {
group.forEach(key => acc[key] = (acc[key] ||
[]).concat({...r}));
return acc;
}, {}))
return res.map(([group, arr]) => ({ group, arr }));
};
console.log(JSON.stringify(groupTogether(arr), undefined, 4));코드 동작 방식
- reduce 단계: 각 객체에서 group 속성을 분리하고({ group, ...r }), 나머지 속성(name, code)만 담은 새 객체를 생성합니다.
- forEach 단계: group 배열의 각 그룹 이름을 순회하면서 누적 객체(acc)에 해당 그룹 키가 없으면 새 배열을 만들고, 이미 있으면 기존 배열에 객체를 추가(concat)합니다. 덕분에 Mercedes처럼 여러 그룹에 속한 객체는 자동으로 모든 그룹에 복사됩니다.
- Object.entries + map 단계: 누적 객체를 [그룹명, 차량 배열] 형태의 엔트리 배열로 변환한 뒤, map으로 { group, arr } 구조의 최종 결과를 만들어 반환합니다.
출력 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
[
{
"group": "Group A",
"arr": [
{
"name": "BMW",
"code": "X821"
}
]
},
{
"group": "Group B",
"arr": [
{
"name": "Audi",
"code": "B216"
},
{
"name": "Ford",
"code": "P385"
},
{
"name": "Mercedes",
"code": "H801"
}
]
},
{
"group": "Group C",
"arr": [
{
"name": "Mercedes",
"code": "H801"
},
{
"name": "Honda",
"code": "C213"
}
]
}
]마무리
이처럼 reduce를 활용하면 중첩된 그룹 속성을 가진 객체 배열도 반복문 없이 선언적으로 깔끔하게 그룹화할 수 있습니다. 실무에서는 카테고리별 상품 분류, 태그별 게시글 묶기 등 다양한 상황에 응용할 수 있으니, 필요에 따라 출력 키 이름(cars, items 등)이나 정렬 방식을 프로젝트 요구 사항에 맞게 조정해 보시기 바랍니다.