如何在JavaScript中向数组添加非重复对象?

3
我希望将非重复对象添加到一个新数组中。
var array = [
  {
    id: 1,
    label: 'one'
  },
  {
    id: 1,
    label: 'one'
  },
  {
    id: 2,
    label: 'two'
  }
];

var uniqueProducts = array.filter(function(elem, i, array) {
    return array.indexOf(elem) === i;
});

console.log('uniqueProducts', uniqueProducts);
// output: [object, object, object] 

{{链接1:实时代码}}

5个回答

4

我喜欢使用ES6的基于类的方法。这个例子使用了lodash的_.isEqual方法来确定对象的相等性。

var array = [{
  id: 1,
  label: 'one'
}, {
  id: 1,
  label: 'one'
}, {
  id: 2,
  label: 'two'
}];

class UniqueArray extends Array {
  constructor(array) {
    super();
    array.forEach(a => {
      if (! this.find(v => _.isEqual(v, a))) this.push(a);
    });
  }
}

var unique = new UniqueArray(array);
console.log(unique);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>


2
您可以使用哈希表并存储找到的id

var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
    uniqueProducts = array.filter(function(elem) {
        return !this[elem.id] && (this[elem.id] = true);
    }, Object.create(null));

console.log('uniqueProducts', uniqueProducts);

检查所有属性

var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
    keys = Object.keys(array[0]),                 // get the keys first in a fixed order
    uniqueProducts = array.filter(function(a) {
        var key = keys.map(function (k) { return a[k]; }).join('|');
        return !this[key] && (this[key] = true);
    }, Object.create(null));

console.log('uniqueProducts', uniqueProducts);


如果我不知道我的键是什么会发生什么?(我没有'id') - undefined
因为你只存储了一次keys,所以{ id: 1, label: 'one' }, { id: 1, label: 'one', test: 2 }将被视为重复项。 - undefined
@user3297291,keys仅包含['id', 'label']key(不带星号)包含不同的值。 - undefined
我的意思是你可以使用第一个对象中的“keys”作为哈希的基础。如果后续的对象是第一个对象的超集(即具有相同的“label”和“id”,但还有其他属性),那么根据你的过滤器,它将不被视为唯一的对象。但我可能说错了。 - undefined
没错,但是在具有相同(可比较)结构的数组中,不太可能有不同的属性计数。 - undefined
同意,这样做没有多大意义。但是对于这种特定情况,“我不知道我的键”这个评论有点自相矛盾 ;) - undefined

2
你可以使用 Object.keys()map() 创建每个对象的键,并使用 filter 去除重复项。

var array = [{
  id: 1,
  label: 'one'
}, {
  id: 1,
  label: 'one'
}, {
  id: 2,
  label: 'two'
}];

var result = array.filter(function(e) {
  var key = Object.keys(e).map(k => e[k]).join('|');
  if (!this[key]) {
    this[key] = true;
    return true;
  }
}, {});

console.log(result)


如果我不知道我的键是什么会发生什么?(我没有'id') - undefined

2
通常,您使用一个对象来跟踪您的唯一键。然后,将对象转换为所有属性值的数组。
最好包括一个类似于唯一的id属性,您可以将其用作标识符。如果没有,您需要使用JSON.stringify或自定义方法自己生成它。字符串化对象将有一个缺点:键的顺序不必保持一致。
您可以创建一个支持深度比较的objectsAreEqual方法,但这会极大地减慢函数速度。
分两步进行:

var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];

// Create a string representation of your object
function getHash(obj) {
   return Object.keys(obj)
     .sort() // Keys don't have to be sorted, do it manually here
     .map(function(k) {
       return k + "_" + obj[k]; // Prefix key name so {a: 1} != {b: 1}
     })
     .join("_"); // separate key-value-pairs by a _
}


function getHashBetterSolution(obj) {
  return obj.id; // Include unique ID in object and use that
};

// When using `getHashBetterSolution`:
// { '1': { id: '1', label: 'one' }, '2': /*etc.*/ }
var uniquesObj = array.reduce(function(res, cur) {
  res[getHash(cur)] = cur;
  return res;
}, {});

// Convert back to array by looping over all keys                             
var uniquesArr =  Object.keys(uniquesObj).map(function(k) {
  return uniquesObj[k];
});

console.log(uniquesArr);

// To show the hashes
console.log(uniquesObj);


如果我不知道我的键是什么会发生什么?(我没有“id”) - undefined
你需要创建一个函数,从任何对象生成一个字符串哈希。如果它们没有嵌套并且只包含基本类型,那么最可能的是将所有属性连接起来。我会提供一个示例。 - undefined

1
你可以使用reduce来提取出唯一的数组和唯一的id,就像这样:

var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];

var result = array.reduce(function(prev, curr) {
  if(prev.ids.indexOf(curr.id) === -1) {
    prev.array.push(curr);
    prev.ids.push(curr.id);
  }
  return prev;
}, {array: [], ids: []});

console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}

如果您不知道键,可以这样做-创建一个唯一的键,帮助您识别重复项-所以我这样做了:
  1. 将对象的键和值的列表连接起来

  2. 现在按照唯一键(如1|id|label|one)对它们进行排序

这处理了对象属性未按顺序排列的情况:

var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];

var result = array.reduce(function(prev, curr) {
  var tracker = Object.keys(curr).concat(Object.keys(curr).map(key => curr[key])).sort().join('|');
  if(!prev.tracker[tracker]) {
    prev.array.push(curr);
    prev.tracker[tracker] = true;
  }
  return prev;
}, {array: [], tracker: {}});

console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接