0

I have an array of objects that can contain duplicates, but I'd like uniquify the array by a property, and then I want to merge properties of the duplicates conditionally. For example, give the array below

var array = [
   {
     name: 'object1',
     propertyA: true,
     propertyB: false,
     propertyC: false 
   },
   {
     name: 'object2',
     propertyA: false,
     propertyB: true,
     propertyC: false
   },
   {
     name: 'object1',
     propertyA: false,
     propertyB: true,
     propertyC: false
   }
]

Knowing each object has name, propertyA, propertyB, and propertyC, I'd like to uniquify by the name property, and keep the true values for propertyA, propertyB, and propertyC. So the above array becomes,

var updatedArray = [
   {
     name: 'object1',
     propertyA: true,
     propertyB: true,
     propertyC: false 
   },
   {
     name: 'object2',
     propertyA: false,
     propertyB: true,
     propertyC: false
   }
]

What is the best way to go about this using lodash/underscore?

frostme
  • 113
  • 2
  • 8

2 Answers2

2

You could do it using _.uniqWith, but it would require you to mutate one of the parameters before returning the boolean value of whether they are equal, so I don't recommend it.

A better option is to use _.groupBy followed by _.map in order to group the unique names, and then customize how you combine them. In your case, you can combine the same-named objects using _.assignWith and then give a logical or || operation as the combining function.

With ES6, it becomes nearly a one-liner:

var array = [{"name":"object1","propertyA":true,"propertyB":false,"propertyC":false},{"name":"object2","propertyA":false,"propertyB":true,"propertyC":false},{"name":"object1","propertyA":false,"propertyB":true,"propertyC":false}];
    
var updatedArray =
  _(array)
    .groupBy('name')
    .map(objs => _.assignWith({}, ...objs, (val1, val2) => val1 || val2))
    .value();
    
console.log(updatedArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
4castle
  • 32,613
  • 11
  • 69
  • 106
  • By the way, [`_.groupBy` and `_.map`, solves all ya problems](http://stackoverflow.com/a/38774930/5743988) (this is a common pattern for problems like this). – 4castle May 09 '17 at 19:41
0

With plain Javascript, you could use a hash table as reference to unique objects with the same name and collect the values in a loop over the keys and update with logical OR.

var array = [{ name: 'object1', propertyA: true, propertyB: false, propertyC: false }, { name: 'object2', propertyA: false, propertyB: true, propertyC: false }, { name: 'object1', propertyA: false, propertyB: true, propertyC: false }],
    unique = array.reduce(function (hash) {
        return function (r, a) {
            if (!hash[a.name]) {
                hash[a.name] = { name: a.name };
                r.push(hash[a.name]);
            }
            Object.keys(a).forEach(function (k) {
                if (k !== 'name') {
                    hash[a.name][k] = hash[a.name][k] || a[k];
                }
            });
            return r;
        };
    }(Object.create(null)), []);

console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392