我有一组数字,我需要确保它们是唯一的。我在互联网上找到了下面的代码片段,它工作得很好,直到数组中有一个零。我在Stack Overflow上找到了另一个脚本,看起来几乎与它完全一样,但它不会失败。

所以为了帮助我学习,有人能帮我确定原型脚本哪里出错吗?

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

重复问题的更多答案:

从JS数组中删除重复值

类似的问题:

获取数组中的所有非唯一值(即:重复/多次出现)


当前回答

这里有一个几乎是一行的O(n),保留了第一个元素,并且在这里你可以将你正在uniq'ing上的字段分开。

这是函数式编程中非常常见的技术——您可以使用reduce来构建返回的数组。因为我们这样构建数组,所以我们保证得到稳定的排序,这与[…new Set(array)]方法不同。我们仍然使用Set来确保没有重复,因此我们的累加器同时包含Set和我们正在构建的数组。

常量删除重复项=(arr)=>减少(([set,acc],item)=>集合有(item)?[set,acc]:[set.add(项目),(acc.push(项目)、acc)],[新设置(),[]])[1]

上述方法适用于简单值,但不适用于对象,类似于[…new Set(array)]的分解方式。如果项目是包含id属性的对象,您应该执行以下操作:

常量删除重复项=(arr)=>减少(([set,acc],item)=>集合有(item.id)?[set,acc]:[set.add(item.id),(acc.push(item),acc)],[新设置(),[]])[1]

其他回答

下面是另一种使用比较器的方法(我更关心干净的代码而不是性能):

const list = [
    {name: "Meier"},
    {name: "Hans"},
    {name: "Meier"},
]
const compare = (a, b) => a.name.localeCompare(b.name);
const uniqueNames = list.makeUnique(compare);
uniqueNames.pushIfAbsent({name: "Hans"}, compare);

原型声明:

declare global {
    interface Array<T>  {
        pushIfAbsent(item: T, compare:(a:T, b:T)=>number): number;
    }
    interface Array<T>  {
        makeUnique(compare:(a:T, b:T)=>number): Array<T>;
    }
}
Array.prototype.pushIfAbsent = function <T>(this:T[], item:T, compare:(a:T, b:T)=>number) {
    if (!this.find(existing => compare(existing, item)===0)) {
        return this.push(item)
    } else {
        return this.length;
    }
}
Array.prototype.makeUnique = function <T>(this:T[], compare:(a:T, b:T)=>number) {
    return this.filter((existing, index, self) => self.findIndex(item => compare(existing, item) == 0) == index);
}

这个不是纯的,它会修改数组,但这是最快的。如果你的速度更快,请写下评论;)

http://jsperf.com/unique-array-webdeb

Array.prototype.uniq = function(){
    for(var i = 0, l = this.length; i < l; ++i){
        var item = this[i];
        var duplicateIdx = this.indexOf(item, i + 1);
        while(duplicateIdx != -1) {
            this.splice(duplicateIdx, 1);
            duplicateIdx = this.indexOf(item, duplicateIdx);
            l--;
        }
    }

    return this;
}

[
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc"
].uniq() //  ["",2,4,"A","abc"]

使用lodash和identity lambda函数执行,只需在使用对象之前定义它

const _ = require('lodash');
...    
_.uniqBy([{a:1,b:2},{a:1,b:2},{a:1,b:3}], v=>v.a.toString()+v.b.toString())
_.uniq([1,2,3,3,'a','a','x'])

并且将具有:

[{a:1,b:2},{a:1,b:3}]
[1,2,3,'a','x']

(这是最简单的方法)

One Liner,纯JavaScript

使用ES6语法

list=list.filter((x,i,a)=>a.indexOf(x)==i)

x --> item in array
i --> index of item
a --> array reference, (in this case "list")

使用ES5语法

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});

浏览器兼容性:IE9+

["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);