我有一组数字,我需要确保它们是唯一的。我在互联网上找到了下面的代码片段,它工作得很好,直到数组中有一个零。我在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数组中删除重复值

类似的问题:

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


当前回答

此脚本修改数组,过滤出重复的值。它适用于数字和字符串。

https://jsfiddle.net/qsdL6y5j/1/

    Array.prototype.getUnique = function () {
        var unique = this.filter(function (elem, pos) {
            return this.indexOf(elem) == pos;
        }.bind(this));
        this.length = 0;
        this.splice(0, 0, unique);
    }

    var duplicates = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
    duplicates.getUnique();
    alert(duplicates);

相反,此版本允许您返回具有唯一值的新数组,该值保持原始值(仅传递true)。

https://jsfiddle.net/dj7qxyL7/

    Array.prototype.getUnique = function (createArray) {
        createArray = createArray === true ? true : false;
        var temp = JSON.stringify(this);
        temp = JSON.parse(temp);
        if (createArray) {
            var unique = temp.filter(function (elem, pos) {
                return temp.indexOf(elem) == pos;
            }.bind(this));
            return unique;
        }
        else {
            var unique = this.filter(function (elem, pos) {
                return this.indexOf(elem) == pos;
            }.bind(this));
            this.length = 0;
            this.splice(0, 0, unique);
        }
    }

    var duplicates = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
    console.log('++++ ovveride')
    duplicates.getUnique();
    console.log(duplicates);
    console.log('++++ new array')
    var duplicates2 = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
    var unique = duplicates2.getUnique(true);
    console.log(unique);
    console.log('++++ original')
    console.log(duplicates2);

Browser support:

Feature Chrome  Firefox (Gecko)     Internet Explorer   Opera   Safari
Basic support   (Yes)   1.5 (1.8)   9                   (Yes)   (Yes)

其他回答

这个原型getUnique并不完全正确,因为如果我有一个类似于[“1”,1,2,3,4,1,“foo”]的数组,它将返回[“1“,“2”,“3”,“4”],“1”是字符串,1是整数;它们是不同的。

以下是正确的解决方案:

Array.prototype.unique = function(a){
    return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });

使用:

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();

以上将产生[“1”,2,3,4,1,“foo”]。

在我的Object用例中,上面的Object答案似乎不适合我。

我修改如下:

var j = {};

this.forEach( function(v) {
   var typ = typeof v;
   var v = (typ === 'object') ? JSON.stringify(v) : v;

   j[v + '::' + typ] = v;
});

return Object.keys(j).map(function(v){
  if ( v.indexOf('::object') > -1 ) {
    return JSON.parse(j[v]);
  }

  return j[v];
});

对于对象、数组、具有混合值的数组、布尔值等,这似乎可以正常工作。

看来我们已经失去了拉斐尔的答案,这是几年来公认的答案。如果没有混合类型数组,这是(至少在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;
}

我知道这个问题已经解决了。。。但是没有人提到linq的javascript实现。然后就可以使用.dispect()方法了,这使得代码非常容易阅读。

var Linq = require('linq-es2015');
var distinctValues =  Linq.asEnumerable(testValues)
            .Select(x)
            .distinct()
            .toArray();

var测试值=[1,2,3,4,5,6,7,8,9,0,1,2,1];var distinctValues=可枚举.asEnumerable(测试值).dispect().toArray();console.log(distinctValues);<script src=“https://npmcdn.com/linq-es5/dist/linq.js“></script>

我查看了Joeytje50在jsperf上的代码,他比较了许多替代方案。他的代码有很多小错误,这对性能和正确性产生了影响。

更重要的是,他正在一个非常小的阵列上进行测试。我用1000个整数组成了一个数组。每个整数是0到1000之间的随机整数的100倍。这使得平均约1000/e=368个重复。结果在jsperf。

这是一个可能需要效率的更现实的场景。这些变化使声明发生了戏剧性的变化(特别是被吹捧为最快的代码远没有快到哪里去)。明显的赢家是使用哈希技术的地方,最好的是

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