获取JavaScript数组中的所有唯一值(删除重复项)

2781
我有一个数字数组,我需要确保其中的数字是唯一的。我在互联网上找到了下面的代码片段,它在数组中有零的情况下工作得很好。我在Stack Overflow上找到了一个几乎完全相似的this other script,但它没有出错。
所以为了帮助我学习,有人可以帮我确定原型脚本出了什么问题吗?
Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

6
那个较旧的问题是关于查找并返回重复项的(我也感到困惑!)。我的问题更多地涉及到为什么此函数在数组中有零时会失败。 - Mottie
对于未来的读者,当你开始发现你必须要以算法方式频繁地修改数据结构的内容(排序、去重等),或者在每次迭代中搜索其中的元素时,可以安全地假设你一开始使用的数据结构是错误的,并开始使用更适合当前任务的数据结构(例如,在这种情况下,使用哈希集合而不是数组)。 - nurettin
我很久以前从别处复制了这段代码...但它似乎非常简单:o表示对象a表示数组i表示索引,而e则表示嗯,某个东西:P - Mottie
使用 Ramda 中的 R.uniq(list) 可以解决这个问题。https://ramdajs.com/docs/#uniq - varad_s
@user6316468 请注意代码部分的重点。火箭表情符号与示例代码无关。抱歉造成困惑。 - Lukas Liesis
显示剩余9条评论
95个回答

16
Array.prototype.getUnique = function() {
    var o = {}, a = []
    for (var i = 0; i < this.length; i++) o[this[i]] = 1
    for (var e in o) a.push(e)
    return a
}

1
我认为如果数组包含对象/数组,则这种方法不起作用,而且我不确定它是否会保留标量的类型。 - Camilo Martin
1
是的,所有东西都会被字符串化。这可以通过将原始值存储在“o”中而不仅仅是“1”来解决,尽管相等比较仍然是按字符串方式进行的(尽管在所有可能的Javascript相等性中,这似乎并不太不合理)。 - ephemient
1
Array.prototype 只能通过非枚举方法进行扩展... Object.defineProperty(Array.prototype,"getUnique",{}) ... 但使用辅助对象的想法非常好。 - bortunac

16

这是因为在JavaScript中,0是一个假值。

如果数组的值为0或任何其他假值,那么this[i]将是假的。


1
啊,我现在明白了...但是有没有简单的解决方法让它工作? - Mottie

14
现在使用集合(set),您可以删除重复项并将它们转换回数组(array)。

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];

console.log([...new Set(names)])

另一种解决方案是使用排序和过滤。

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
var namesSorted = names.sort();
const result = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);
console.log(result);


13
如果你正在使用Prototype框架,就不需要使用'for'循环了,你可以像这样使用http://prototypejs.org/doc/latest/language/Array/prototype/uniq/
var a = Array.uniq();  

这将产生一个没有重复项的副本数组。我在寻找一种计算不同数组记录数的方法时遇到了你的问题,所以在使用 uniq() 之后我使用了 size(),得到了简单的结果。

附:如果您想要排除未定义的记录,您可能需要在之前添加 compact(),就像这样:

var a = Array.compact().uniq();  

15
因为我找到了更好的答案,所以我认为这些话题适用于所有人,而不仅仅是提问者。 - Decebal
2
感谢时光机,但据我所知大约15年前JS社区曾经进行过辩论,结果是不要扩展原型,因为会产生副作用并且会以这种方式污染所有的JS数组。 - Lukas Liesis

12

我遇到了一个略微不同的问题,需要从数组中删除具有重复id属性的对象。这个方案有效。

let objArr = [{
  id: '123'
}, {
  id: '123'
}, {
  id: '456'
}];

objArr = objArr.reduce((acc, cur) => [
  ...acc.filter((obj) => obj.id !== cur.id), cur
], []);

console.log(objArr);


9

如果你不介意使用额外的依赖项,或者你已经在你的代码库中有其中一个库,你可以使用LoDash(或Underscore)来就地从数组中删除重复项。

用法

如果你还没有它,请使用npm安装它:

npm install lodash

然后按以下方式使用它:
import _ from 'lodash';
let idArray = _.uniq ([
    1,
    2,
    3,
    3,
    3
]);
console.dir(idArray);

输出:

[ 1, 2, 3 ]

您还可以使用lodash从数组中删除具有重复属性的对象:_.uniqWith(objectArray, _.isEqual) - Mike

8
我不确定为什么Gabriel Silveira会写出那样的函数,但我使用一个同样简单且没有缩小的形式也能正常工作:
Array.prototype.unique = function() {
  return this.filter(function(value, index, array) {
    return array.indexOf(value, index + 1) < 0;
  });
};

或者使用CoffeeScript编写:
Array.prototype.unique = ->
  this.filter( (value, index, array) ->
    array.indexOf(value, index + 1) < 0
  )

7

简单方法查找唯一的数组值

function arrUnique(a){
  var t = [];
  for(var x = 0; x < a.length; x++){
    if(t.indexOf(a[x]) == -1)t.push(a[x]);
  }
  return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]

这个答案怎么可能是正确的?根据给定的输入[1,4,2,7,1,5,9,2,4,7,2],唯一数组的期望结果应该是[5,9]。 - Pooja Thapa
@PoojaThapa 这将从输入数组中提取唯一值。 - Saravanan Rajaraman

7

在ES6或更新版本中

获取唯一的值

  let a = [
           { id: 1, name: "usman" },
           { id: 2, name: "zia" },
           { id: 3, name: "usman" },
          ];
const unique = [...new Set(a.map((item) => item.name))];
console.log(unique); // ["usman", "zia"]

获取唯一对象

const myObjArray = [
                       { id: 1, name: "usman" },
                       { id: 2, name: "zia" },
                       { id: 3, name: "usman" },
                   ];
// Creates an array of objects with unique "name" property values.
let uniqueObjArray = [
  ...new Map(myObjArray.map((item) => [item["name"], item])).values(),
];

console.log("uniqueObjArray", uniqueObjArray);

7

看起来我们失去了Rafael的答案,它曾经是几年来被接受的答案。这是(至少在2017年)最好的解决方案如果你没有混合类型的数组

Array.prototype.getUnique = function(){
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
return a;
}

如果您有一个混合类型的数组,可以对哈希键进行序列化:

Array.prototype.getUnique = function() {
    var hash = {}, result = [], key; 
    for ( var i = 0, l = this.length; i < l; ++i ) {
        key = JSON.stringify(this[i]);
        if ( !hash.hasOwnProperty(key) ) {
            hash[key] = true;
            result.push(this[i]);
        }
    }
    return result;
}

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