실무에서는 여러 개의 객체가 들어 있는 배열을 하나의 객체로 재구성해야 하는 경우가 종종 있습니다. 예를 들어, 다음과 같이 학생 정보를 담은 객체 배열이 있다고 가정해 보겠습니다.
const arr = [{
name: 'A',
idNo: 1,
marks: {
math: 98,
sci: 97,
eng: 89
}
},
{
name: 'B',
idNo: 2,
marks: {
math: 88,
sci: 87,
eng: 79
}
},
{
name: 'C',
idNo: 3,
marks: {
math: 87,
sci: 98,
eng: 91
}
}];문제 정의
요구 사항은 이러한 배열을 인수로 받는 자바스크립트 함수를 작성하는 것입니다. 함수는 원본 객체들이 가지고 있는 각 키(name, idNo, marks)마다 하나의 속성을 갖는 새로운 객체를 만들어야 하며, 각 속성의 값에는 기존 객체들의 해당 값들이 순서대로 배열에 담겨 있어야 합니다.
따라서 위 배열에 대한 최종 출력 결과는 다음과 같은 형태가 되어야 합니다.
const output = {
name: ['A', 'B', 'C'],
idNo: [1, 2, 3],
marks: [{
math: 98,
sci: 97,
eng: 89
},
{
math: 88,
sci: 87,
eng: 79
},
{
math: 87,
sci: 98,
eng: 91
}]
};예제 코드
이 문제는 배열 메서드인 reduce()와 Object.keys()를 조합하면 깔끔하게 해결할 수 있습니다. 구현 코드는 다음과 같습니다.
const arr = [{
name: 'A',
idNo: 1,
marks: {
math: 98,
sci: 97,
eng: 89
}
},
{
name: 'B',
idNo: 2,
marks: {
math: 88,
sci: 87,
eng: 79
}
},
{
name: 'C',
idNo: 3,
marks: {
math: 87,
sci: 98,
eng: 91
}
}];
const combineMarks = (arr = []) => {
let res = [];
res = arr.reduce((acc, val) => {
Object.keys(val).forEach(el => {
if (!acc[el]) {
acc[el] = [];
};
acc[el].push(val[el])
});
return acc;
}, {});
return res;
};
console.log(combineMarks(arr));코드 동작 원리
reduce()는 배열을 처음부터 끝까지 순회하면서 누적 객체(acc)를 점진적으로 채워 나갑니다. 초기값으로 빈 객체{}를 전달합니다.- 순회 중인 각 객체에 대해
Object.keys(val)로 모든 키를 추출하고,forEach()로 하나씩 처리합니다. - 현재 키가 누적 객체에 아직 없다면
if (!acc[el])조건을 통해 빈 배열로 초기화한 뒤, 해당 키의 값을push()로 추가합니다. - 모든 요소를 순회하고 나면 키별로 값들이 모인 단일 객체가 완성되어 반환됩니다.
출력 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
{
name: [ 'A', 'B', 'C' ],
idNo: [ 1, 2, 3 ],
marks: [
{ math: 98, sci: 97, eng: 89 },
{ math: 88, sci: 87, eng: 79 },
{ math: 87, sci: 98, eng: 91 }
]
}이처럼 reduce()를 활용하면 객체 배열의 구조를 유지하면서도 키를 기준으로 데이터를 손쉽게 재배열할 수 있습니다. 이 패턴은 API 응답 데이터를 그룹화하거나 차트용 데이터셋을 만들 때 특히 유용하게 사용됩니다.