19

My collection looks like this.

  var list = [{id:'12345', sequence:null}, {id:'12346', sequence:null}, {id:'12347', sequence:null}, {id:'12348', sequence:1}, {id:'12348', sequence:2}, {id:'12349', sequence:1}, {id:'12349', sequence:1}];

I am trying to get a unique list so that object with same id AND sequence will only return one of the objects (we have 2 here- {id:'12349', sequence:1})

my code

  var uniqueList = _.uniq(list, function(obj) {
    return obj.id && obj.sequence;
  });

can we use lodash uniq like this? what is the approach to fix this issue?

Sanath
  • 4,774
  • 10
  • 51
  • 81

3 Answers3

45

You can use uniqBy() to compute the criterion by which the list is generated wherein the iteratee callback returns the joined value of id and sequence of each item of the colection. The solution below works great when you only want to have specific properties to be the criterion of uniqueness especially when each object in your collection may not only have the id and sequence properties.

var result = _.uniqBy(list, v => [v.id, v.sequence].join());

var list = [{
  id: '12345',
  sequence: null
}, {
  id: '12346',
  sequence: null
}, {
  id: '12347',
  sequence: null
}, {
  id: '12348',
  sequence: 1
}, {
  id: '12348',
  sequence: 2
}, {
  id: '12349',
  sequence: 1
}, {
  id: '12349',
  sequence: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 2
}];

var result = _(list)
  .uniqBy(v => [v.id, v.sequence].join())
  .value();

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.js"></script>

Alternatively, if you have properties that contains non-primitive values (objects or arrays) to be used as the criterion then you can still use the solution above but instead joining the array of values, you have to use JSON.stringify()

var result = _.uniqBy(list, v => JSON.stringify([v.id, v.sequence]));

var list = [{
  id: '12345',
  sequence: null
}, {
  id: '12346',
  sequence: null
}, {
  id: '12347',
  sequence: null
}, {
  id: '12348',
  sequence: 1
}, {
  id: '12348',
  sequence: 2
}, {
  id: '12349',
  sequence: 1
}, {
  id: '12349',
  sequence: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 2
}];

var result = _.uniqBy(list, v => JSON.stringify([v.id, v.sequence]));

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.js"></script>

UPDATE:

For the lodash3 solution, for properties with primitive values, you can still use the pattern in the first solution using uniq().

var result = _.uniq(list, v => [v.id, v.sequence].join());

var list = [{
  id: '12345',
  sequence: null
}, {
  id: '12346',
  sequence: null
}, {
  id: '12347',
  sequence: null
}, {
  id: '12348',
  sequence: 1
}, {
  id: '12348',
  sequence: 2
}, {
  id: '12349',
  sequence: 1
}, {
  id: '12349',
  sequence: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 2
}];

var result = _.uniq(list, v => [v.id, v.sequence].join());

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

And for the non-primitive properties, you can still use the 2nd example above with uniq()

var result = _.uniq(list, v => JSON.stringify([v.id, v.sequence]));

var list = [{
  id: '12345',
  sequence: null
}, {
  id: '12346',
  sequence: null
}, {
  id: '12347',
  sequence: null
}, {
  id: '12348',
  sequence: 1
}, {
  id: '12348',
  sequence: 2
}, {
  id: '12349',
  sequence: 1
}, {
  id: '12349',
  sequence: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 1
}, {
  id: '123490',
  sequence: 1,
  extra: 2
}];

var result = _.uniq(list, v => JSON.stringify([v.id, v.sequence]));

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
ryeballar
  • 29,658
  • 10
  • 65
  • 74
  • Thanks for this awesome answer. sadly my project uses lodash 3 so that UniqWith and UniqBy can't be used. It seems that I have to use Pure javascript for this then. – Sanath May 19 '16 at 12:47
  • 1
    What happens when [id,sequence] are like [1,23] and [12,3] - both are returned right? – Vamshi Vangapally Aug 02 '20 at 21:43
3

You may use uniqWith

This method is like _.uniq except that it accepts comparator which is invoked to compare elements of array. The comparator is invoked with two arguments: (arrVal, othVal).

and isEqual

Performs a deep comparison between two values to determine if they are equivalent.

_.uniqWith(list, _.isEqual);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

No.Use uniqWith. And write correct comparator with same signature as isEqual.

Artem Markov
  • 413
  • 3
  • 13