Search code examples
javascriptarrayslodasharray-merge

How to use Lodash's unionBy and merge nested arrays?


Im looking to merge/combine objects in an array each with a series of nested arrays. I want to merge the objects based on a specific key (here label[1]). I can use Lodash and unionBy to filter out dublicates by label[1], but how do i keep the values from the filtered items?

The array can look like this:

var arr = [{
    "label": ['item', 'private'],
    "values": [1, 2, 3]
  },
  {
    "label": ['item', 'private'],
    "values": [1, 2, 3, 6]
  },
  {
    "label": ['item', 'work'],
    "values": [1, 2, 8, 9]
  },
  {
    "label": ['item', 'private'],
    "values": [1, 2, 4, 5]
  },
  {
    "label": ['item', 'school'],
    "values": [1, 2, 7]
  }
];

And the desired output is:

var arr = [{
  "label": ["item", "private"],
  "values": [1, 2, 3, 4, 5, 6 ]
}, {
  "label": ["item", "work"],
  "values": [1, 2, 8, 9]
}, {
  "label": ["item", "school"],
  "values": [1, 2, 7]
}]

Here's a sample which is only half way there.

var arr = [
  { label: ['item','private'], values: [1,2,3] },
  { label: ['item','private'], values: [1,2,3,6] },
  { label: ['item','work'], values: [1,2,8,9] },
  { label: ['item','private'], values: [1,2,4,5] },
  { label: ['item','school'], values: [1,2,7] }
];

var result = _.unionBy(arr, "label[1]");

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Any ideas?

Thanks Lasse


Solution

  • Not sure how to do this with lodash but I don't think unionBy is the method to do this anyway.

    Here is how you can group by label using lodash and then reduce the groups into one value to merge the items of a group.

    const arr = [{"label":["item","private"],"values":[1,2,3]},{"label":["item","private"],"values":[1,2,3,6]},{"label":["item","work"],"values":[1,2,8,9]},{"label":["item","private"],"values":[1,2,4,5]},{"label":["item","school"],"values":[1,2,7]}];
    
    console.log(
      Object.values(
        _.groupBy(arr, (item) => item.label.join()),//use lodash group by
      ).map((
        group, //now we have array of array of groups
      ) =>
        group
          .reduce((result, item) => ({
            //reduce a group to one object
            label: result.label, //set label
            values: [
              //set values with unique values of all items
              ...new Set(
                (result.values || []).concat(item.values || []),
              ),
            ],
          })),
      ),
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>