【问题标题】:How can I uniquely union two array of objects?如何唯一地联合两个对象数组?
【发布时间】:2018-01-21 19:04:02
【问题描述】:

我正在尝试在不使用 lodash 的 unionBy 方法的情况下合并两个对象数组。

目前我的以下代码运行良好:

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');

这个输出:

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

这是想要的结果,但我不能在我当前的工作环境中使用unionBy,所以我正在寻找使用原生 JS 或其他 lodash 方法 3.6.0 或更低版本的结果。

【问题讨论】:

  • 如何在自己的代码中实现unionBy 的基础知识?

标签: javascript arrays lodash


【解决方案1】:

Concat 并使用 Array#filter 和辅助对象来删除重复项:

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);

如果 ES6 是一个选项,您可以使用 Set 代替辅助对象:

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);

如果要使用箭头函数,则不能使用Array.filter()thisArgSet绑定为函数的this(不能将this绑定到箭头职能)。您可以改用闭包(该方法的属性转到 @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);

【讨论】:

  • 工作完美且易于理解!
  • 有没有用箭头函数写这个?这里的“this”是数组本身,对吧?它有效,但一点解释会很可爱,谢谢。
  • this 是对象或集合。 Array.filter() 方法接受 thisArg,并将其绑定到回调。它不能是箭头函数。我将添加一个使用闭包的示例,该闭包使用箭头函数和 Set。
  • "set => o =>" 这部分让我很困惑,o 是这个集合的成员的代表,但是这里的集合规则是什么?对不起,我有点菜鸟。
  • 哦,我明白了,它实际上是另一个函数中的一个函数,你这样做是为了访问作为 set 成员的对象的成员。set 是第一个函数的参数然后 o是第二个函数的参数。
【解决方案2】:

您可以使用Set 进行过滤以获取唯一值。

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);

【讨论】:

    【解决方案3】:

    您可以为此使用 ES6 Map。使用数据构造它,以a 属性值为键,然后再次将值从 Map 中取出:

    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);

    【讨论】:

      【解决方案4】:

      您可以合并两个数组,然后过滤具有相同属性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)

      如果您仍然希望能够指定联合的属性,您可以像这样实现自己的功能:

      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);

      注意:与某些答案相比,我的答案的一个优点是它保留了 lodash 中的顺序,这可能很重要,也可能不重要。

      【讨论】:

        【解决方案5】:

        ES5 使用 Array.filterArray.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 箭头函数

        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"));

        另一个 ES6 单行实验

        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"));

        【讨论】:

          【解决方案6】:

          你可以巧妙地使用 ES6 的 find 和 reduce 函数!

          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);

          【讨论】:

            猜你喜欢
            • 2019-05-05
            • 1970-01-01
            • 2022-01-04
            • 2016-05-28
            • 2022-01-04
            • 1970-01-01
            • 2023-03-19
            相关资源
            最近更新 更多