JavaScript 개발을 하다 보면 여러 개의 객체가 담긴 배열을, 각 키를 기준으로 값들을 묶어 놓은 하나의 객체 형태로 바꿔야 하는 경우가 종종 있습니다. 예를 들어 날짜별 데이터가 여러 객체에 흩어져 있을 때, 이를 날짜를 키로 하는 배열로 재구성하면 이후 데이터를 조회하거나 가공하기가 훨씬 수월해집니다.
문제 상황
다음과 같이 날짜를 키로 하는 객체들이 담긴 배열이 있다고 가정해 보겠습니다.
const nights = [
{ "2016-06-25": 32, "2016-06-26": 151, "2016-06-27": null },
{ "2016-06-24": null, "2016-06-25": null, "2016-06-26": null },
{ "2016-06-26": 11, "2016-06-27": 31, "2016-06-28": 31 },
];
우리가 작성할 함수는 이런 배열을 입력받아, 객체의 키를 기준으로 값을 모아 배열 객체(object of arrays)를 만들어야 합니다.
즉, 위 배열에 대한 최종 결과는 다음과 같은 형태가 되어야 합니다.
const output = {
"2016-06-24": [null],
"2016-06-25": [32, null],
"2016-06-26": [151, null, 11],
"2016-06-27": [null, 31],
"2016-06-28": [31]
};
구현 방법
핵심 로직은 생각보다 단순합니다. 원본 배열을 순회하면서 각 객체의 키 목록을 확인하고, 결과 객체에 해당 키가 이미 존재하면 값을 추가(push)하고, 존재하지 않으면 새 배열을 만들어 할당하면 됩니다.
const nights = [
{ "2016-06-25": 32, "2016-06-26": 151, "2016-06-27": null },
{ "2016-06-24": null, "2016-06-25": null, "2016-06-26": null },
{ "2016-06-26": 11, "2016-06-27": 31, "2016-06-28": 31 },
];
const arrayToObject = (arr = []) => {
const res = {};
for(let i = 0; i < arr.length; i++){
const keys = Object.keys(arr[i]);
for(let j = 0; j < keys.length; j++){
if(res.hasOwnProperty(keys[j])){
res[keys[j]].push(arr[i][keys[j]]);
}
else{
res[keys[j]] = [arr[i][keys[j]]];
}
}
};
return res;
};
console.log(arrayToObject(nights));
코드 살펴보기
- Object.keys() — 각 객체가 가진 키 목록을 배열 형태로 반환합니다.
- hasOwnProperty() — 결과 객체에 해당 키가 이미 존재하는지 확인합니다. 키가 있으면 기존 배열에 값을 추가하고, 없으면 새 배열을 생성해 할당합니다.
- 바깥쪽 for 문은 원본 배열의 요소(객체)를 순회하고, 안쪽 for 문은 각 객체의 키를 하나씩 처리합니다.
실행 결과
코드를 실행하면 콘솔에 다음과 같이 출력됩니다.
{
'2016-06-25': [ 32, null ],
'2016-06-26': [ 151, null, 11 ],
'2016-06-27': [ null, 31 ],
'2016-06-24': [ null ],
'2016-06-28': [ 31 ]
}
출력 결과를 보면 키가 입력 데이터에서 처음 등장한 순서대로 배치되어 있는데, 이는 JavaScript 객체가 문자열 키를 삽입 순서대로 유지하기 때문입니다. 키의 나열 순서는 다를 수 있어도, 각 날짜별로 값이 정확하게 그룹화되었다는 점은 동일합니다. 이처럼 반복문과 Object.keys(), hasOwnProperty()만 활용하면 별도의 외부 라이브러리 없이도 객체 배열을 손쉽게 배열 객체로 변환할 수 있습니다.