Merge array of objects with array values into a single object

99 Views Asked by At

Using plain JavaScript or lodash, what's the easiest way to transform an array of objects into a single object, while concatenating any array values?

I can achieve it on a single property using _.flatMap(before, "nodes") but not sure how to include all properties.

For example:

const before = [
  {
    nodes: [
      { "id": "1" },
      { "id": "2" }
    ],
    links: [
      { "source": "1", "target": "2" }
    ],
  },
  {
    nodes: [
        { "id": "3" },
        { "id": "4" },
        { "id": "5" },
        { "id": "6" }
    ],
    links: [
      { "source": "3", "target": "4" },
      { "source": "5", "target": "6" }
    ],
  }
];

const after = {
  nodes: [
    { "id": "1" },
    { "id": "2" },
    { "id": "3" },
    { "id": "4" },
    { "id": "5" },
    { "id": "6" }
  ],
  links: [
    { "source": "1", "target": "2" },
    { "source": "3", "target": "4" },
    { "source": "5", "target": "6" }
  ],
};
5

There are 5 best solutions below

0
DecPK On BEST ANSWER

You can achieve this using vanilla js using reduce and Object.entries as:

const before = [
    {
        nodes: [
            { "id": "1" },
            { "id": "2" }
        ],
        links: [
            { "source": "1", "target": "2" }
        ],
    },
    {
        nodes: [
            { "id": "3" },
            { "id": "4" },
            { "id": "5" },
            { "id": "6" }
        ],
        links: [
            { "source": "3", "target": "4" },
            { "source": "5", "target": "6" }
        ],
    }
];

const result = before.reduce((acc, curr) => {
    Object.entries(curr).forEach(([key, value]) => {
        acc[key] = [ ...(acc[key] ?? []), ...value];
    })
    return acc;
}, {});

console.log(result);

0
Jiraiya On

Since you want to merge array into one, you should use reduce instead of map. Following should work

after = before.reduce((prevResult, element) => {
    var newResult = {}
    Object.keys(element).forEach((key) => {
        newResult[key] = prevResult[key].concat(element[key])
    })
    return newResult
})

reduce will work with each element in iterative manner from left to right.

Hope this helps

0
Manuvo On

One possible solution using lodash:

const after = _.reduce(before, (acc, curr) => {
  _.forOwn(curr, (value, key) => {
    acc[key] = _.concat(acc[key] || [], value);
  });
  
  return acc;
}, {});

The result is a new object that contains these combined arrays.

0
Ali Yaghoubi On
const before = [
  {
    nodes: [
      { "id": "1" },
      { "id": "2" }
    ],
    links: [
      { "source": "1", "target": "2" }
    ],
  },
  {
    nodes: [
        { "id": "3" },
        { "id": "4" },
        { "id": "5" },
        { "id": "6" }
    ],
    links: [
      { "source": "3", "target": "4" },
      { "source": "5", "target": "6" }
    ],
  }
];

Following below code:

const flatData = (data) => {
    const result = { nodes : [], links: [] };

    for (let i = 0; i < data.length; i++) {
        const {nodes, links} = data[i]; // nodes and links

        // nodes
        for (let i = 0; i < nodes.length; i++) {
            result.nodes = [...result.nodes, nodes[i]];
        }

        // links
        for (let i = 0; i < links.length; i++) {
            result.links = [...result.links, nodes[i]];
        }
    }

    return result;
}
0
Abin Thaha On

You can use Array.reduce() to achieve this efficiently.

Please find the following code:

const before = [{
    nodes: [{
        "id": "1"
      },
      {
        "id": "2"
      }
    ],
    links: [{
      "source": "1",
      "target": "2"
    }],
  },
  {
    nodes: [{
        "id": "3"
      },
      {
        "id": "4"
      },
      {
        "id": "5"
      },
      {
        "id": "6"
      }
    ],
    links: [{
        "source": "3",
        "target": "4"
      },
      {
        "source": "5",
        "target": "6"
      }
    ],
  }
];

const after = before.reduce((acc, curr) => {
    Object.keys(curr).forEach(key => {
        acc[key] = [...acc[key] , ...curr[key]]
    })
    return acc;
})
console.log("After is ===>>", after);