最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I uniquely union two array of objects? - Stack Overflow

programmeradmin1浏览0评论

I am trying to merge two arrays of objects without using the unionBy method from lodash.

Currently I have the following code working perfectly:

var array1 = [
 { a: 1, b: 'first'},
 { a: 2, b: 'second'}
];

var array2 = [
 { a: 3, b: 'third'},
 { a: 1, b: 'fourth'}
];

var array3 = __.unionBy(array2, array1, 'a');

This outputs:

[
  {
    "a": 3,
    "b": "third"
  },
  {
    "a": 1,
    "b": "fourth"
  },
  {
    "a": 2,
    "b": "second"
  }
]

This is the desired result but I can't use unionBy in my current work environment, so I'm looking for a result that uses either native JS or other lodash methods 3.6.0 or lower.

I am trying to merge two arrays of objects without using the unionBy method from lodash.

Currently I have the following code working perfectly:

var array1 = [
 { a: 1, b: 'first'},
 { a: 2, b: 'second'}
];

var array2 = [
 { a: 3, b: 'third'},
 { a: 1, b: 'fourth'}
];

var array3 = __.unionBy(array2, array1, 'a');

This outputs:

[
  {
    "a": 3,
    "b": "third"
  },
  {
    "a": 1,
    "b": "fourth"
  },
  {
    "a": 2,
    "b": "second"
  }
]

This is the desired result but I can't use unionBy in my current work environment, so I'm looking for a result that uses either native JS or other lodash methods 3.6.0 or lower.

Share Improve this question asked Jan 21, 2018 at 19:04 zeckdudezeckdude 16.2k44 gold badges146 silver badges194 bronze badges 1
  • 1 how about implementing the basics of unionBy in your own code? – Jason Commented Jan 21, 2018 at 19:07
Add a comment  | 

6 Answers 6

Reset to default 10

Concat and use Array#filter with a helper object to remove duplicates:

var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];

var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

var result = array2.concat(array1).filter(function(o) {  
  return this[o.a] ? false : this[o.a] = true;
}, {});

console.log(result);

If ES6 is an option you can use a Set instead of the helper object:

const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];

const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

const result = array2.concat(array1).filter(function(o) {  
  return this.has(o.a) ? false : this.add(o.a);
}, new Set());

console.log(result);

If you want to use an arrow function, you can't use the thisArg of Array.filter() to bind the Set as the this of the function (you can't bind this to arrow functions). You can use a closure instead (attribute for the method goes to @NinaScholz).

const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];

const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

const result = [...array2, ...array1]
  .filter((set => // store the set and return the actual callback
      o => set.has(o.a) ? false : set.add(o.a)
    )(new Set()) // use an IIFE to create a Set and store it set
  );

console.log(result);

You can use an ES6 Map for this. Construct it with the data, keyed by the a property value, and then take the values out of the Map again:

var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}],
    array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

var result = [...new Map([...array1,...array2].map( o => [o.a, o] )).values()];

console.log(result);

You could take a Set for filtering to get unique values.

var array1 = [{ a: 1, b: 'first' }, { a: 2, b: 'second' }],
    array2 = [{ a: 3, b: 'third' }, { a: 1, b: 'fourth' }],
    s = new Set,
    array3 = array2.map(o => (s.add(o.a), o)).concat(array1.filter(o => !s.has(o.a)));

console.log(array3);

You can merge the 2 arrays and then filter the ones with same property a:

var array1 = [{ a: 1, b: 'first'},{ a: 2, b: 'second'}],
  array2 = [{ a: 3, b: 'third'},{ a: 1, b: 'fourth'}],
  array3 = [...array2, ...array1].filter((item, pos, arr) =>
    arr.findIndex(item2 => item.a == item2.a) == pos);

console.log(array3)

If you want to still be able to specify the property by which to union you can implement you own function like this:

var array1 = [{ a: 1, b: 'first'},{ a: 2, b: 'second'}],
  array2 = [{ a: 3, b: 'third'},{ a: 1, b: 'fourth'}],
  array3 = unionBy(array1, array2, 'a');

function unionBy(array1, array2, prop){
  return [...array2, ...array1].filter((item, pos, arr) =>
      arr.findIndex(item2 => item[prop] == item2[prop]) == pos);
}

console.log(array3);

Note: One advantage of my answer over some of the answers is that it preserves the order like in lodash which may or may not be important.

ES5 using Array.filter and Array.find

var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];

var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];

function merge(a, b, prop) {
  var reduced = a.filter(function(itemA) {
return !b.find(function(itemB) {
  return itemA[prop] === itemB[prop];
});
  });
  return reduced.concat(b);
}

console.log(merge(array1, array2, "a"));

ES6 arrow functions

var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];

var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];

function merge(a, b, prop) {
  const reduced = a.filter(
itemA => !b.find(itemB => itemA[prop] === itemB[prop])
  );
  return reduced.concat(b);
}

console.log(merge(array1, array2, "a"));

Another ES6 one line experiment

var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];

var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];

const merge = (a, b, p) => a.filter( aa => ! b.find ( bb => aa[p] === bb[p]) ).concat(b);

console.log(merge(array1, array2, "a"));

You could use ES6 find and reduce function smartly!

var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var res = array1.concat(array2).reduce((aggr, el)=>{
    if(!aggr.find(inst=>inst.a==el.a))
        return [...aggr, el];
    else
        return aggr
},[])

console.log(res);

发布评论

评论列表(0)

  1. 暂无评论