Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

underscore/lodash unique by multiple properties

I have an array of objects with duplicates and I'm trying to get a unique listing, where uniqueness is defined by a subset of the properties of the object. For example,

{a:"1",b:"1",c:"2"} 

And I want to ignore c in the uniqueness comparison.

I can do something like

_.uniq(myArray,function(element) { return element.a + "_" + element+b}); 

I was hoping I could do

_.uniq(myArray,function(element) { return {a:element.a, b:element.b} }); 

But that doesn't work. Is there something like that I can do, or do I need to create a comparable representation of the object if I'm comparing multiple properties?

like image 878
Jeff Storey Avatar asked Oct 10 '14 19:10

Jeff Storey


People also ask

Is Lodash compatible with underscore?

Lodash's API is a superset of Underscore. It provides every functionality that Underscore does, along with a few additional helpful functions such as AMD support, deep clone, and deep merge.

Which is better underscore or Lodash?

I am stunned right now, seeing a Lodash performing 100-150% faster than Underscore. js in even simple, native functions such as Array. every in Chrome!

What is _ get?

The _. get() function is an inbuilt function in the Underscore. js library of JavaScript which is used to get the value at the path of object. If the resolved value is undefined, the defaultValue is returned in its place. Syntax: _.get(object, path, [defaultValue])

Is Lodash still needed?

But Sometimes You Do Need Lodash Not every Lodash utility is available in Vanilla JavaScript. You can't deep clone an object, for example. That's why these libraries are far from obsolete. But if you're loading the entire library just to use a couple of methods, that's not the best way to use the library.


2 Answers

There doesn't seem to be a straightforward way to do this, unfortunately. Short of writing your own function for this, you'll need to return something that can be directly compared for equality (as in your first example).

One method would be to just .join() the properties you need:

_.uniqBy(myArray, function(elem) { return [elem.a, elem.b].join(); }); 

Alternatively, you can use _.pick or _.omit to remove whatever you don't need. From there, you could use _.values with a .join(), or even just JSON.stringify:

_.uniqBy(myArray, function(elem) {     return JSON.stringify(_.pick(elem, ['a', 'b'])); }); 

Keep in mind that objects are not deterministic as far as property order goes, so you may want to just stick to the explicit array approach.

P.S. Replace uniqBy with uniq for Lodash < 4

like image 80
voithos Avatar answered Sep 20 '22 07:09

voithos


Use Lodash's uniqWith method:

_.uniqWith(array, [comparator])

This method is like _.uniq except that it accepts comparator which is invoked to compare elements of array. The order of result values is determined by the order they occur in the array. The comparator is invoked with two arguments: (arrVal, othVal).

When the comparator returns true, the items are considered duplicates and only the first occurrence will be included in the new array.


Example:
I have a list of locations with latitude and longitude coordinates -- some of which are identical -- and I want to see the list of locations with unique coordinates:

const locations = [   {     name: "Office 1",     latitude: -30,     longitude: -30   },   {     name: "Office 2",     latitude: -30,     longitude: 10   },   {     name: "Office 3",     latitude: -30,     longitude: 10   } ];  const uniqueLocations = _.uniqWith(   locations,   (locationA, locationB) =>     locationA.latitude === locationB.latitude &&     locationA.longitude === locationB.longitude );  // Result has Office 1 and Office 2 
like image 20
Reed Dunkle Avatar answered Sep 18 '22 07:09

Reed Dunkle