두 개의 배열이 있다고 가정해 보겠습니다. 첫 번째 배열에는 여러 이벤트의 예정된 날짜가 담겨 있고, 두 번째 배열에는 그 이벤트들의 이름이 담겨 있습니다.
const dates = [
{
id:"1",
date:"2017-11-07"
},
{
id:"1",
date:"2017-11-08"
},
{
id:"2",
date:"2017-11-07"
},
{
id:"2",
date:"2017-11-08"
}
];
const names = [
{
id:"1",
name:"Pervies, Peter"
},
{
id:"2",
name:"Ming, Edmund"
}
];
여기서 필요한 것은 이 두 배열을 입력으로 받아 id 속성을 기준으로 이벤트 이름과 그에 해당하는 날짜들을 하나로 묶어 주는 JavaScript 함수입니다.
따라서 위와 같은 배열이 주어졌을 때 최종 출력 결과는 다음 형태가 되어야 합니다.
const output = [
{
id:"1",
name:"Pervies, Peter",
details:[
{date:"2017-11-07"},
{date:"2017-11-08"}
]
},
{
id:"2",
name:"Ming, Edmund",
details:[
{date:"2017-11-07"},
{date:"2017-11-08"}
]
}
];
구현 예제
이를 구현한 전체 코드는 다음과 같습니다.
const combineArrays = (dates, names) => {
const res = [];
dates.forEach(el => {
const bool = !res.some(item => {
return item.id == el.id;
});
if(bool){
let combined = {};
combined.id = el.id;
combined.details = combined.details || [];
combined.details.push({
"date": el.date
});
res.push(combined);
}else{
res.find(item => {
return item.id === el.id;
})
.details.push({
"date": el.date
});
};
});
res.forEach(el => {
const bool = names.some(item => {
return item.id === el.id;
});
if(bool){
el.name = names.find(name => {
return name.id === el.id;
}).name;
};
});
return res;
};
console.log(JSON.stringify(combineArrays(dates, names), undefined, 4));
출력 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{
"id": "1",
"details": [
{
"date": "2017-11-07"
},
{
"date": "2017-11-08"
}
],
"name": "Pervies, Peter"
},
{
"id": "2",
"details": [
{
"date": "2017-11-07"
},
{
"date": "2017-11-08"
}
],
"name": "Ming, Edmund"
}
]
코드 동작 방식
combineArrays 함수는 크게 두 단계로 동작합니다.
- 1단계 – 날짜 그룹화: dates 배열을 순회하면서 각 요소의 id가 결과 배열(res)에 이미 존재하는지 확인합니다. 존재하지 않으면 새로운 객체를 생성해 details 배열에 날짜를 추가하고, 이미 존재한다면 해당 객체의 details 배열에 날짜만 이어서 추가합니다.
- 2단계 – 이름 매핑: 완성된 결과 배열을 다시 순회하면서 names 배열에서 같은 id를 가진 항목을 찾아 name 속성을 할당합니다.
더 간결한 대안: Map 활용하기
ES6 문법을 활용하면 위 로직을 더욱 간결하고 효율적으로 작성할 수 있습니다. 특히 데이터 양이 많을 때는 some, find 같은 배열 메서드를 반복 호출하는 것보다 Map을 사용하는 것이 성능 면에서 유리합니다.
const combineArrays = (dates, names) => {
const map = new Map();
dates.forEach(({ id, date }) => {
if (!map.has(id)) {
map.set(id, { id, details: [] });
}
map.get(id).details.push({ date });
});
return [...map.values()].map(item => ({
...item,
name: names.find(n => n.id === item.id)?.name
}));
};
console.log(JSON.stringify(combineArrays(dates, names), undefined, 4));
두 방법 모두 동일한 결과를 반환하지만, Map 기반 접근 방식은 키 조회 시간이 거의 일정(O(1))하기 때문에 대량의 데이터를 처리할 때 더 나은 선택입니다.