在JavaScript数组中收集唯一对象

时间:2016-03-31 22:33:12

标签: javascript arrays

假设我有以下对象数组

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),即

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'}
];

我可以用

收集ALL
Array.prototype.unshift.apply(firstDataSet , secondDataSet );

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

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

4 个答案:

答案 0 :(得分:3)

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

这是原始问题

使用Set

  

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

var list = ["{'id': 123, 'name': 'ABC'}", "{'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!

有关构建数组的更多方法,可以按照here的说明进行操作。 如果您无法使用ES6(定义{{​​1}}的内容),则可以使用旧版浏览器polyfill

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

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

解决此类问题的最简单方法是迭代对象数组,识别具有重复属性值的对象,并使用Set进行消除。

答案 1 :(得分:1)

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

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。在这种情况下,必要时重写/填充/转换。

答案 2 :(得分:0)

这可能不是最有效的解决方案,但假设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');

答案 3 :(得分:0)

这可以通过扩展如下的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))

工作link