繁体   English   中英

收集 JavaScript 数组中的唯一对象

[英]Collect unique objects in JavaScript array

假设我有以下对象数组

var firstDataSet = [
  {'id': 123, 'name': 'ABC'},
  {'id': 456, 'name': 'DEF'},
  {'id': 789, 'name': 'GHI'},
  {'id': 101, 'name': 'JKL'}
];

var secondDataSet = [
  {'id': 123, 'name': 'ABC', 'xProp': '1q'},
  {'id': 156, 'name': 'MNO', 'xProp': '2w'},
  {'id': 789, 'name': 'GHI', 'xProp': '3e'},
  {'id': 111, 'name': 'PQR', 'xProp': '4r'}
];

现在我想收集具有唯一对象的数组(匹配idname )ie

var firstDataSet = [
  {'id': 123, 'name': 'ABC', 'xProp': '1q'},
  {'id': 456, 'name': 'DEF'},
  {'id': 789, 'name': 'GHI', 'xProp': '3e'},
  {'id': 101, 'name': 'JKL'},
  {'id': 156, 'name': 'MNO', 'xProp': '2w'},
  {'id': 111, 'name': 'PQR', 'xProp': '4r'}
];

我可以收集所有

Array.prototype.unshift.apply(firstDataSet , secondDataSet );

但不确定如何过滤掉重复项。 有什么建议吗?

编辑:我在两个不同阵列上的对象不一样。 至少基于属性的数量。

删除具有所有相同属性的重复项

这是最初的问题

使用Set

Set 对象允许您存储任何类型的唯一值,无论是原始值还是对象引用。

您还可以使用对象字面量。

var list = [JSON.stringify({id: 123, 'name': 'ABC'}), JSON.stringify({id: 123, 'name': 'ABC'})]; 
var unique_list = new Set(list); // returns Set {"{'id': 123, 'name': 'ABC'}"}
var list = Array.from(unique_list); // converts back to an array, and you can unstringify the results accordingly.

有关将集合构造回数组的更多方法,您可以按照此处的说明进行操作。 如果您不能使用 ES6(它定义了Set ),则有一个适用于旧浏览器的polyfill


删除具有重复属性子集的对象

不幸的是,这些对象不再是严格重复的,并且不能使用Set以友好的方式处理,例如。

解决此类问题的最简单方法是遍历对象数组,识别具有重复属性值的对象,并使用splice就地消除,例如。

这可以通过扩展Set类来实现,如下所示

    var firstDataSet = [
      {'id': 123, 'name': 'ABC'},
      {'id': 456, 'name': 'DEF'},
      {'id': 789, 'name': 'GHI'},
      {'id': 101, 'name': 'JKL'}
    ];

    var secondDataSet = [
      {'id': 123, 'name': 'ABC', 'xProp': '1q'},
      {'id': 156, 'name': 'MNO', 'xProp': '2w'},
      {'id': 789, 'name': 'GHI', 'xProp': '3e'},
      {'id': 111, 'name': 'PQR', 'xProp': '4r'}
    ];

    Array.prototype.unshift.apply(firstDataSet , secondDataSet );

    //console.log(firstDataSet)

    class UniqueSet extends Set {
            constructor(values) {
                super(values);

                const data = [];
                for (let value of this) {
                    if (data.includes(JSON.parse(value.id))) {
                        this.delete(value);
                    } else {
                        data.push(value.id);
                    }
                }
            }
          }

console.log(new UniqueSet(firstDataSet))

工作链接

这可能不是最有效的解决方案,但假设 id 总是唯一的,它应该可以工作。

var firstDataSet = [
  {'id': 123, 'name': 'ABC'},
  {'id': 456, 'name': 'DEF'},
  {'id': 789, 'name': 'GHI'},
  {'id': 101, 'name': 'JKL'}
];

var secondDataSet = [
  {'id': 123, 'name': 'ABC', 'xProp': '1q'},
  {'id': 156, 'name': 'MNO', 'xProp': '2w'},
  {'id': 789, 'name': 'GHI', 'xProp': '3e'},
  {'id': 111, 'name': 'PQR', 'xProp': '4r'}
];

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

function concatUnique(a, b, property) {
    var arr = a.concat(b);
    arr.sort(function(a,b) { 
        return Object.keys(b).length - Object.keys(a).length; 
    });
    var ids = arr.map(function(obj){ return obj[property] }).unique();

    return arr.filter(function(obj) { 
        if(ids.indexOf(obj[property]) > -1) { 
            ids.splice( ids.indexOf(obj[property]) , 1); 
            return true; 
        } else { 
            return false 
        }
    });
}

var newArray = concatUnique(firstDataSet, secondDataSet, 'id');

我们将使用concat组合两个数组,然后使用filter过滤结果数组。 对于每个元素,我们将使用findIndex找到具有相同 id 和 name 的第一个元素的索引。 如果该索引与当前索引相同,则表示这是该 id 和 name 的第一次出现,因此我们就让它通过。 否则,我们将在第一次出现的地方添加新字段,并将其过滤掉。

function combine(a1, a2) {

  function match(e1, e2) { return e1.id === e2.id && e1.name === e2.name); }

  return a1.concat(a2) . filter((e1, i, a) => {
    let firstIndex = a.findIndex(e2 => match(e1, e2));
    if (i === firstIndex) return true; // this is the first occurrence
    a[firstIndex].xProp = e2.xProp;    // copy over property
    return false;                      // filter out
  });

}

如果您想处理任意属性,而不仅仅是xProp ,则将相关行更改为类似

a[firstIndex] = Object.assign(e2, a[firstIndex]);

这将替换第一次出现的结果,将其所有属性复制到当前出现的顶部,包括它可能具有的任何其他属性。

强制性免责声明:一如既往,根据您的环境,您可能没有箭头函数、 Array#findIndexObject.assign 在这种情况下,根据需要重写/polyfill/transpile。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM