Skoby
Skoby

Reputation: 171

How to get unique array from nested object with lodash

My collection contains the following (array of objects):

[
    {
        id: 'id-1',
        uniqueName: 'operation-level-1',
        operations: [
            {
                name: 'operaion-1',
                label: 'operation-1-label'
            },
            {
                name: 'operaion-2',
                label: 'operation-2-label'
            }
        ]
    },
    {
        id: 'id-2',
        uniqueName: 'operation-level-2'
        operations: [
            {
                name: 'operaion-1',
                label: 'operation-1-label'
            },
            {
                name: 'operaion-3',
                label: 'operation-3-label'
            }
        ]
    }

]

I wanted to get an array of unique operation name and label as shown below

const result = [
    {
        name: 'operaion-1',
        label: 'operation-1-label'
    },
    {
        name: 'operaion-2',
        label: 'operation-2-label'
    },
    {
        name: 'operaion-3',
        label: 'operation-3-label'
    }
]

Can someone suggest the best way to achieve this, please?

Upvotes: 2

Views: 2948

Answers (3)

Ori Drori
Ori Drori

Reputation: 191976

Use _.flatMap() to get a flattened array of operations, and then use _.uniqBy() to get only items with unique name:

const data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];

const result =  _.uniqBy(
  _.flatMap(data, 'operations'),
  'name'
);

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

With lodash/fp you can generate a function using _.flow() that flattens operations, and then get the unique values by name:

const fn = _.flow(
  _.flatMap('operations'),
  _.uniqBy('name')
)

const data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];

const result = fn(data);

console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

Upvotes: 5

Rajneesh
Rajneesh

Reputation: 5308

This can be easily done without lodash. You can first flat the data then map it as a key value pair and then make use of Map to remove the duplicate entries:

var data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];

var result =  [...new Map(data.flatMap(({operations})=>operations).map(k=>([k.name, k]))).values()];

console.log(result);

Or if you do not want to use Map then use filter method:

var data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];

var result = data.flatMap(({operations})=>operations).filter((val,i,self)=>self.findIndex(j=>j.name==val.name && j.label==val.label)==i);

console.log(result);

Upvotes: 6

Orelsanpls
Orelsanpls

Reputation: 23505

There is no need for loadash, a simple Map object, will allow you to suppress the duplicates.

const arr = [{
    id: 'id-1',
    uniqueName: 'operation-level-1',
    operations: [{
        name: 'operaion-1',
        label: 'operation-1-label'
      },
      {
        name: 'operaion-2',
        label: 'operation-2-label'
      }
    ]
  },
  {
    id: 'id-2',
    uniqueName: 'operation-level-2',
    operations: [{
        name: 'operaion-1',
        label: 'operation-1-label'
      },
      {
        name: 'operaion-3',
        label: 'operation-3-label'
      }
    ]
  }
];

// Go thought the arr and add all the name/label into the map
// Then use Array.from to reformate the Map into the wanted format
const uniqueArr = Array.from(arr.reduce((tmp, {
  operations,
}) => {
  operations.forEach(({
    name,
    label,
  }) => {
    tmp.set(name, label);
  });

  return tmp;
}, new Map())).map(([name, label]) => ({
  name,
  label,
}));

console.log(uniqueArr);

Upvotes: 0

Related Questions