Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flatten nested objects with lodash

I'm banging my head against a well trying to do the following with lodash. I have an array of objects with more nested objects, which looks like this:

[{
    id: 123,
    name: 'John',
    summary1: {
        count: 3,
        sum: 10,
    },
    summary2: {
        count: 10,
        sum: 20
    },
},
...
]

I want to convert each element of this array into something like this:

[{
    id: 123,
    name: 'John',
    summary1_count: 3,
    summary1_sum: 10
    summary2_count: 10,
    summary2_sum: 20,
},
...
]

SO basically I want to "flatten" each element of the array, in a way such that object keys are determined based on the main and subkeys. How can I accomplish this using lodash or plain JS?

You can assume there's just 1 level of nesting like in the example.

like image 250
user3856970 Avatar asked May 19 '17 17:05

user3856970


People also ask

How do you flatten objects in Lodash?

The Lodash. flatten() method is used to flatten the array to one level deep. Parameter: This method accepts single parameter array that holds simple array or array of arrays. Return Value: The return type of this function is array.

How do you flatten an array of objects?

You use the flat() method for concatenating sub-arrays recursively into a single array. The flat() method takes a depth value as its parameter which is optional depending on the depth of the array you wish to flatten (concatenate). The flat() method takes in 1 as a depth by default.


1 Answers

You can simply use the npm package flat.

import flat from 'flat';

const array = [
  {
    a: 'a',
    b: {
      bb: 'bb',
    },
    c: {
      cc1: 'cc1',
      cc: {
        ccc: 'ccc',
        ccd: 'ccd',
      },
    },
  },
  // ...
];

const flattenedArray = array.map(flat);

/*
  flattenedArray === [
    {
      a: 'a',
      b.bb: 'bb',
      c.cc1: 'cc1',
      c.cc.ccc: 'ccc',
      c.cc.ccd: 'ccd',
    },
    // ...
  ]
*/

And if you want to implement it yourself, here's my implementation of flat:

const flat = (obj, concatenator = '.') => (
  Object.keys(obj).reduce(
    (acc, key) => {
      if (typeof obj[key] !== 'object' || !obj[key]) {
        return {
          ...acc,
          [key]: obj[key],
        };
      }

      const flattenedChild = flat(obj[key], concatenator);

      return {
        ...acc,
        ...Object.keys(flattenedChild).reduce((childAcc, childKey) => ({ ...childAcc, [`${key}${concatenator}${childKey}`]: flattenedChild[childKey] }), {}),
      };
    },
    {},
  )
);

const flattenedArray = array.map(o => flat(o));

Those solutions will work with any depth.

like image 87
fxlemire Avatar answered Oct 02 '22 16:10

fxlemire