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

JavaScript에서 중첩 배열 쌍을 객체 배열로 변환하는 방법

배열 안에 배열이 중첩된 형태의 데이터를 다루다 보면, 이를 사람이 읽기 쉬운 객체(object) 형태로 바꿔야 하는 경우가 자주 있습니다. 이번 글에서는 키-값 쌍으로 이루어진 중첩 배열을 객체 배열로 변환하는 방법을 알아보겠습니다.

문제 상황

다음과 같이 배열 안에 배열이 중첩된 데이터가 있다고 가정해 보겠습니다.

const arr = [
   [
      ['firstName', 'Joe'],
      ['lastName', 'Blow'],
      ['age', 42],
      ['role', 'clerk'],
      [
         ['firstName', 'Mary'],
         ['lastName', 'Jenkins'],
         ['age', 36],
         ['role', 'manager']
      ]
   ]
];

각 요소는 [키, 값] 형태의 쌍이며, 그중 하나는 또 다른 쌍들의 배열, 즉 새로운 사용자 정보로 되어 있습니다. 우리가 작성할 함수는 이런 배열을 입력받아 고유한 사용자마다 하나의 객체를 갖는 배열을 반환해야 합니다.

따라서 기대하는 출력 결과는 다음과 같습니다.

const output = [
   { firstName: 'Joe', lastName: 'Blow', age: 42, role: 'clerk' },
   { firstName: 'Mary', lastName: 'Jenkins', age: 36, role: 'manager' }
];

재귀 함수를 이용한 해결 방법

배열의 중첩 깊이가 정해져 있지 않으므로 재귀(recursion)로 접근하는 것이 가장 안전합니다. 요소의 첫 번째 값이 문자열이면 키-값 쌍으로 처리하고, 배열이면 새로운 사용자 그룹으로 판단해 재귀 호출하는 방식입니다.

const convertToObject = (data) => {
   const result = [];
   let current = {};

   // 지금까지 모은 속성으로 객체를 완성해 결과에 추가
   const flush = () => {
      if (Object.keys(current).length) {
         result.push(current);
         current = {};
      }
   };

   const build = (items) => {
      items.forEach((item) => {
         if (Array.isArray(item[0])) {
            // 중첩 배열을 만나면 현재 객체를 먼저 저장한 뒤
            flush();
            // 새로운 사용자로 처리하기 위해 재귀 호출
            build(item);
         } else {
            // 일반적인 [키, 값] 쌍인 경우
            current[item[0]] = item[1];
         }
      });
      flush();
   };

   build(data);
   return result;
};

console.log(convertToObject(arr));

출력 결과

[
   { firstName: 'Joe', lastName: 'Blow', age: 42, role: 'clerk' },
   { firstName: 'Mary', lastName: 'Jenkins', age: 36, role: 'manager' }
]

코드 동작 원리

핵심 로직은 다음과 같습니다.

  • current 객체: 배열을 순회하면서 키-값 쌍을 하나씩 모아 두는 임시 객체입니다.
  • flush() 함수: current에 담긴 속성이 있으면 result에 저장한 뒤 초기화합니다.
  • 중첩 배열 판별: Array.isArray(item[0])로 첫 번째 요소가 배열인지 확인하고, 배열이라면 지금까지의 객체를 마무리한 후 해당 배열을 새로운 사용자로 재귀 처리합니다.

주의할 점

변환 과정에서 하나의 객체를 계속 재사용하거나 참조를 공유하면 모든 속성이 하나의 객체에 뒤섞이는 오류가 발생할 수 있습니다. 반드시 사용자 단위로 새로운 객체를 만들어 결과에 추가해야 합니다.

참고: 단순 배열이라면 Object.fromEntries 활용

중첩 없이 단순한 키-값 쌍 배열만 있다면 ES2019에서 도입된 Object.fromEntries()로 한 줄로 해결할 수 있습니다.

const pairs = [['firstName', 'Joe'], ['lastName', 'Blow'], ['age', 42]];
const obj = Object.fromEntries(pairs);

console.log(obj);
// { firstName: 'Joe', lastName: 'Blow', age: 42 }

다만 Object.fromEntries()는 중첩 구조를 사용자 단위로 분리해 주지 않으므로, 위 예제처럼 여러 명의 정보가 섞여 있는 데이터에는 앞서 소개한 재귀 방식이 적합합니다.