代码之家  ›  专栏  ›  技术社区  ›  Mottie

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

  •  1014
  • Mottie  · 技术社区  · 15 年前

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

    重复问题的更多答案:

    类似问题:

    66 回复  |  直到 5 年前
        1
  •  1891
  •   Thomas Ruiz    6 年前

    JavaScript 1.6 / ECMAScript 5 你可以用本地的 filter 数组的方法,方法如下,以获取具有唯一值的数组:

    function onlyUnique(value, index, self) { 
        return self.indexOf(value) === index;
    }
    
    // usage example:
    var a = ['a', 1, 'a', 2, '1'];
    var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
    

    本机方法 滤波器 将循环遍历数组并只保留那些通过给定回调函数的条目 onlyUnique .

    唯一的 检查给定值是否是第一个发生的值。如果没有,它必须是一个副本,并且不会被复制。

    此解决方案不需要任何额外的库(如jquery或prototype.js)即可工作。

    它也适用于混合值类型的数组。

    对于不支持本机方法的旧浏览器(<ie9) 滤波器 indexOf 您可以在MDN文档中找到 filter indexOf .

    如果要保留值的最后一次出现,只需替换 索引 通过 lastIndexOf .

    使用ES6,可以缩短为:

    // usage example:
    var myArray = ['a', 1, 'a', 2, '1'];
    var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); 
    
    // unique is ['a', 1, 2, '1']
    

    多亏了 Camilo Martin 以获取注释中的提示。

    ES6具有本机对象 Set 存储唯一值。要获取具有唯一值的数组,现在可以执行以下操作:

    var myArray = ['a', 1, 'a', 2, '1'];
    
    let unique = [...new Set(myArray)]; 
    
    // unique is ['a', 1, 2, '1']
    

    的建设者 设置 接受一个不可重复的对象,如数组和排列运算符 ... 将集合转换回数组。多亏了 Lukas Liese 以获取注释中的提示。

        2
  •  643
  •   A.T.    7 年前

    更新了ES6/ES2015的答案 使用 Set ,单线解决方案为:

    var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
    var uniqueItems = Array.from(new Set(items))
    

    哪些回报

    [4, 5, 6, 3, 2, 23, 1]
    

    AS le_m 建议,也可以使用 spread operator ,就像

    var uniqueItems = [...new Set(items)]
    
        3
  •  126
  •   Ruslan López ampachts    7 年前

    您也可以使用 underscore.js .

    console.log(_.uniq([1, 2, 1, 3, 1, 4]));
    <script src="http://underscorejs.org/underscore-min.js"></script>

    将返回:

    [1, 2, 3, 4]
    
        4
  •  118
  •   Community Ramakrishna.p    7 年前

    我知道这个问题已经有30多个答案了。但是,我首先通读了所有现有的答案,并进行了自己的研究。

    我将所有答案分为4个可能的解决方案:

    1. 使用新的ES6功能: […new set([1,1,2])];
    2. 使用对象来防止重复
    3. 使用helper数组
    4. 使用 filter+indexof

    以下是答案中的示例代码:

    使用新的ES6功能: […new set([1,1,2])];

    函数uniquearray0(array){
    var result=array.from(new set(array));
    返回结果
    }
    < /代码> 
    
    

    使用对象来防止重复

    函数uniquearray1(ar){
    变量j=
    
    Ar.ForEach(功能(V){
    J[V+':'+类型V]=V;
    (});
    
    返回对象.键(j).map(函数(v){
    返回J[V];
    (});
    }
    < /代码> 
    
    

    使用helper数组

    函数uniquearray2(arr){
    var a= [];
    对于(var i=0,l=arr.length;i<l;i++)
    如果(a.indexof(arr[i])==-1&&arr[i]!=='')
    A.推动(arr[i]);
    返回A;
    }
    < /代码> 
    
    

    使用filter+indexof

    函数uniquearray3(a){
    函数OnlyUnique(值、索引、自身){
    返回self.indexof(value)==索引;
    }
    
    /使用
    var unique=a.filter(onlyunique);//返回['a',1,2,'1']
    
    返回唯一;
    }
    < /代码> 
    
    

    我想知道哪一个更快。我已经制作了sample google sheetto test functions.注意:ECMA 6在Google工作表中不可用,因此我无法测试它。

    测试结果如下:

    我希望看到使用对象的代码会赢,因为它使用哈希。因此,我很高兴测试在Chrome和IE中显示了此算法的最佳结果。感谢@rab for

    我将所有答案分为4个可能的解决方案:

    1. 使用新的ES6功能:[...new Set( [1, 1, 2] )];
    2. 使用对象{ }防止重复
    3. 使用助手数组[ ]
    4. 使用filter + indexOf

    以下是答案中的示例代码:

    使用新的ES6功能:[…新集合([1,1,2]);

    function uniqueArray0(array) {
      var result = Array.from(new Set(array));
      return result    
    }
    

    使用对象{}防止重复

    function uniqueArray1( ar ) {
      var j = {};
    
      ar.forEach( function(v) {
        j[v+ '::' + typeof v] = v;
      });
    
      return Object.keys(j).map(function(v){
        return j[v];
      });
    } 
    

    使用助手数组[]

    function uniqueArray2(arr) {
        var a = [];
        for (var i=0, l=arr.length; i<l; i++)
            if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
                a.push(arr[i]);
        return a;
    }
    

    使用筛选+索引

    function uniqueArray3(a) {
      function onlyUnique(value, index, self) { 
          return self.indexOf(value) === index;
      }
    
      // usage
      var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
    
      return unique;
    }
    

    我想知道哪一个更快。我已经做了sample Google Sheet测试功能。注意:ECMA 6在谷歌表单中不可用,所以我无法测试它。

    测试结果如下: enter image description here

    我希望看到使用对象的代码{}会赢,因为它使用哈希。因此,我很高兴测试在Chrome和IE中显示了该算法的最佳结果。the code.

        5
  •  52
  •   Vamsi    8 年前

    一行,纯javascript

    使用ES6语法

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

    数组中的项目 i——项目索引 一个-->数组引用(在本例中为“list”)。 < /代码>

    使用ES5语法

    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")
    

    enter image description here

    用ES5语法

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

    浏览器兼容性IE9+

        6
  •  50
  •   Mottie    12 年前

    从那以后,我发现了一个使用jquery的好方法

    arr = $.grep(arr, function(v, k){
        return $.inArray(v ,arr) === k;
    });
    

    注意:此代码是从 Paul Irish's duck punching post -我忘记给学分了:P

        7
  •  45
  •   gregers    9 年前

    ES6最短解决方案: [...new Set( [1, 1, 2] )];

    或者,如果要修改数组原型(如原始问题):

    Array.prototype.getUnique = function() {
        return [...new Set( [this] )];
    };
    

    ECMAScript 6仅 partially implemented 在当前的现代浏览器中(2015年8月),但是 Babel 已经成为非常流行的发泄ES6(甚至ES7)回到ES5。这样,您就可以在今天编写ES6代码了!

    如果你想知道 ... 意思是,它被称为 spread operator . 从 MDN :_«Spread运算符允许在需要多个参数(用于函数调用)或多个元素(用于数组文本)的位置扩展表达式»。因为集合是可iterable(并且只能有唯一的值),所以spread运算符将展开集合以填充数组。

    学习ES6的资源:

        8
  •  32
  •   Ruslan López ampachts    7 年前

    最简单的解决方案:

    var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
    console.log([...new Set(arr)]);

    或:

    var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
    console.log(Array.from(new Set(arr)));
        9
  •  30
  •   Joeytje50    11 年前

    最简单的,和 fastest (铬)这样做的方式:

    Array.prototype.unique = function() {
        var a = [];
        for (var i=0, l=this.length; i<l; i++)
            if (a.indexOf(this[i]) === -1)
                a.push(this[i]);
        return a;
    }
    

    只需遍历数组中的每个项,测试该项是否已经在列表中,如果没有,则推送到返回的数组。

    根据jspef,此函数是 the fastest of the ones I could find anywhere -尽管如此,请随意添加您自己的。

    非原型版本:

    function uniques(arr) {
        var a = [];
        for (var i=0, l=arr.length; i<l; i++)
            if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
                a.push(arr[i]);
        return a;
    }
    

    分选

    当还需要对数组进行排序时,以下是最快的:

    Array.prototype.sortUnique = function() {
        this.sort();
        var last_i;
        for (var i=0;i<this.length;i++)
            if ((last_i = this.lastIndexOf(this[i])) !== i)
                this.splice(i+1, last_i-i);
        return this;
    }
    

    或非原型:

    function sortUnique(arr) {
        arr.sort();
        var last_i;
        for (var i=0;i<arr.length;i++)
            if ((last_i = arr.lastIndexOf(arr[i])) !== i)
                arr.splice(i+1, last_i-i);
        return arr;
    }
    

    这也是 faster than the above method 在大多数非Chrome浏览器中。

        10
  •  28
  •   Community Ramakrishna.p    7 年前

    仅限表演!这个代码可能比这里所有代码快10倍 *适用于所有浏览器,并且内存影响最小…. 还有更多

    如果不需要重用旧数组,那么在将其转换为唯一数组之前,顺便做一些必要的其他操作,这可能是最快的方法,也非常短。

    var array=[1,2,3,4,5,6,7,8,9,0,1,2,1];
    

    那你可以试试这个

    var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];
    
    function toUnique(a, b, c) { //array,placeholder,placeholder
      b = a.length;
      while (c = --b)
        while (c--) a[b] !== a[c] || a.splice(c, 1);
      return a // not needed ;)
    }
    console.log(toUnique(array));
    //[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]

    我在阅读这篇文章时想到了这个函数…

    http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/

    我不喜欢for循环。它有很多参数,我喜欢while循环。 在所有浏览器中,除了我们都非常喜欢的浏览器外,它是最快的循环…铬。

    不管怎样,我编写了第一个使用while的函数。是的,它比本文中的函数快一点,但还不够。 unique2()

    下一步使用现代JS。 Object.keys 我用js1.7的object.keys替换了另一个for循环… 稍微快一点,再短一点(铬合金比铬合金快两倍);)。还不够!. unique3() .

    在这一点上,我在思考我的独特功能到底需要什么。 我不需要旧的数组,我想要一个快速函数。 所以我用了2个while循环+拼接。 unique4()

    没必要说我印象深刻。

    铬: 通常每秒150000次操作跃升到每秒1800000次操作。

    IE: 80000次/秒vs 3500000次/秒

    网间网操作系统: 18000 op/s对170000 op/s

    游猎: 80000次/秒vs 6000000次/秒

    证明 http://jsperf.com/wgu 或者最好使用控制台。时间…微时间…无论什么

    unique5() 只是告诉你如果你想保留旧数组会发生什么。

    不要使用 Array.prototype 如果你不知道你在做什么。 我只是抄了很多过去。 使用 Object.defineProperty(Array.prototype,...,writable:false,enumerable:false}) 如果要创建本机原型。示例: https://stackoverflow.com/a/20463021/2450730

    演示 http://jsfiddle.net/46S7g/

    注意:在执行此操作后,旧数组将被销毁/成为唯一数组。

    如果你不能阅读上面的代码,请阅读一本javascript书籍,或者这里有一些关于较短代码的解释。 https://stackoverflow.com/a/21353032/2450730

    一些正在使用 indexOf …不要。。。 http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

    对于空数组

    !array.length||toUnique(array); 
    
        11
  •  24
  •   Community Ramakrishna.p    7 年前

    这里的许多答案可能对初学者没有用处。如果一个数组的重复数据消除很困难,他们真的知道原型链,甚至jquery吗?

    在现代浏览器中,一个干净而简单的解决方案是将数据存储在 Set ,设计为唯一值列表。

    const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
    const uniqueCars = Array.from(new Set(cars));
    

    这个 Array.from 将集合转换回数组非常有用,这样您就可以轻松访问数组所具有的所有出色方法(功能)。也有 other ways 做同样的事情。但你可能不需要 来自… 因为集合有很多有用的特性,比如 forEach .

    如果您需要支持旧的Internet Explorer,因而不能使用set,那么一种简单的技术是将项目复制到新的数组中,同时预先检查它们是否已经在新的数组中。

    // Create a list of cars, with duplicates.
    var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
    // Create a list of unique cars, to put a car in if we haven't already.
    var uniqueCars = [];
    
    // Go through each car, one at a time.
    cars.forEach(function (car) {
        // The code within the following block runs only if the
        // current car does NOT exist in the uniqueCars list
        // - a.k.a. prevent duplicates
        if (uniqueCars.indexOf(car) === -1) {
            // Since we now know we haven't seen this car before,
            // copy it to the end of the uniqueCars list.
            uniqueCars.push(car);
        }
    });
    

    为了使这个可以立即重用,让我们把它放到一个函数中。

    function deduplicate(data) {
        if (data.length > 0) {
            var result = [];
    
            data.forEach(function (elem) {
                if (result.indexOf(elem) === -1) {
                    result.push(elem);
                }
            });
    
            return result;
        }
    }
    

    为了消除重复,我们现在就这么做。

    var uniqueCars = deduplicate(cars);
    

    这个 deduplicate(cars) 部分 变成 我们命名的东西 结果 当函数完成时。

    只要把你喜欢的数组的名字传给它。

        12
  •  19
  •   sergeyz    10 年前
    ["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;
     }, []);
    
        13
  •  17
  •   Gajus    10 年前

    这个原型 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"] .

        14
  •  12
  •   Cœur N0mi    11 年前

    如果不扩展array.prototype(据说这是一个糟糕的实践)或使用jquery/underline,您只需 filter 数组。

    通过保留最后一个事件:

        function arrayLastUnique(array) {
            return array.filter(function (a, b, c) {
                // keeps last occurrence
                return c.indexOf(a, b + 1) < 0;
            });
        },
    

    或第一次出现:

        function arrayFirstUnique(array) {
            return array.filter(function (a, b, c) {
                // keeps first occurrence
                return c.indexOf(a) === b;
            });
        },
    

    好吧,它只是JavaScriptECMAScript 5+,这意味着只有IE9+,但它很适合在原生HTML/JS(Windows应用商店应用程序、Firefox OS、Sencha、PhoneGap、Titanium…)中进行开发。

        15
  •  12
  •   Gufran Hasan    6 年前

    我们可以使用ES6设置:

    var duplicatedArray = [1,2,3,4,5,1,1,1,2,3,4];
    var uniqueArray = Array.from(new Set(duplicatedArray));
    

    //输出将为

    uniqueArray = [1,2,3,4,5];
    
        16
  •  10
  •   Luca Matteis    15 年前

    那是因为 0 是javascript中的错误值。

    this[i] 如果数组的值为0或任何其他错误值,则为错误。

        17
  •  10
  •   Decebal    13 年前

    如果您使用的是原型框架,那么不需要执行“for”循环,您可以使用 http://www.prototypejs.org/api/array/uniq 这样地:

    var a = Array.uniq();  
    

    它将生成一个没有重复项的重复数组。我发现你的问题是在寻找一种方法来计算不同的数组记录,所以

    单位()

    我用过

    尺寸()

    这是我的简单结果。 对不起,如果我打错了什么

    编辑:如果要转义未定义的记录,可以添加

    紧致()

    之前,像这样:

    var a = Array.compact().uniq();  
    
        18
  •  9
  •   ephemient    15 年前
    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
    }
    
        19
  •  6
  •   Dan Fox    11 年前

    我不知道为什么加布里埃尔·席尔维拉这样写这个函数,但是一个简单的形式,对我来说也同样有效,没有缩小是:

    Array.prototype.unique = function() {
      return this.filter(function(value, index, array) {
        return array.indexOf(value, index + 1) < 0;
      });
    };
    

    或在咖啡中描述:

    Array.prototype.unique = ->
      this.filter( (value, index, array) ->
        array.indexOf(value, index + 1) < 0
      )
    
        20
  •  6
  •   Saravanan Rajaraman    9 年前

    在简单方法中查找唯一数组值

    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]
    
        21
  •  6
  •   daviestar    7 年前

    奇怪的是,以前没有人建议过……按对象键删除重复项( id 下面)在一个数组中,您可以这样做:

    const uniqArray = array.filter((obj, idx, arr) => (
      arr.findIndex((o) => o.id === obj.id) === idx
    )) 
    
        22
  •  6
  •   Kamil Kiełczewski    6 年前

    魔术

    a.filter(( t={}, e=>!(t[e]=e in t) )) 
    

    o(n) performance ;我们假设您的数组在 a . 解释 here (+ Jeppe 改进

    var a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];
    var a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12]];
    var a3 = ['Mike', 'Adam','Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];
    
    let nd = (a) => a.filter((t={},e=>!(t[e]=e in t))) 
    
    
    // print
    let c= x => console.log(JSON.stringify(x));             
    c( nd(a1) );
    c( nd(a2) );
    c( nd(a3) );
        23
  •  5
  •   Maxime Pacary    12 年前

    Shamasis Bhattacharya 's blog (o(2n)时间复杂性):

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

    Paul Irish 's blog :jquery的改进 .unique() :

    (function($){
    
        var _old = $.unique;
    
        $.unique = function(arr){
    
            // do the default behavior only if we got an array of elements
            if (!!arr[0].nodeType){
                return _old.apply(this,arguments);
            } else {
                // reduce the array to contain no dupes via grep/inArray
                return $.grep(arr,function(v,k){
                    return $.inArray(v,arr) === k;
                });
            }
        };
    })(jQuery);
    
    // in use..
    var arr = ['first',7,true,2,7,true,'last','last'];
    $.unique(arr); // ["first", 7, true, 2, "last"]
    
    var arr = [1,2,3,4,5,4,3,2,1];
    $.unique(arr); // [1, 2, 3, 4, 5]
    
        24
  •  5
  •   Le Droid    9 年前

    相反地,为了解决这个问题,在加载数组时不重复可能很有用,方法是 Set 对象将执行此操作,但它在所有浏览器中都不可用。它节省了内存,如果您需要多次查看其内容,它会更高效。

    Array.prototype.add = function (elem) {
       if (this.indexOf(elem) == -1) {
          this.push(elem);
       }
    }
    

    Sample:

    set = [];
    [1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });
    

    给你 set = [1,3,4,2]

        25
  •  3
  •   Torbjörn Nomell    11 年前

    如果有人使用 knockoutjs

    ko.utils.arrayGetDistinctValues()
    

    顺便看看 ko.utils.array* 公用事业。

        26
  •  3
  •   Jason    11 年前

    我发现序列化散列键有助于我为对象工作。

    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;
        }
    
        27
  •  3
  •   kornfridge    11 年前

    您也可以使用 sugar.js:

    [1,2,2,3,1].unique() // => [1,2,3]
    
    [{id:5, name:"Jay"}, {id:6, name:"Jay"}, {id: 5, name:"Jay"}].unique('id') 
      // => [{id:5, name:"Jay"}, {id:6, name:"Jay"}]
    
        28
  •  3
  •   Constant Meiring    6 年前

    如果您对额外的依赖关系还满意,或者您的代码库中已经有了一个库,那么您可以使用lodash(或下划线)从一个数组中删除重复项。

    用法

    如果您的代码库中没有它,请使用NPM安装它:

    npm install lodash
    

    然后如下使用:

    import _ from 'lodash';
    let idArray = _.uniq ([
        1,
        2,
        3,
        3,
        3
    ]);
    console.dir(idArray);
    

    出:

    [ 1, 2, 3 ]
    
        29
  •  3
  •   Zoe - Save the data dump 张群峰    5 年前

    基于ES6的解决方案…

    var arr = [2,3,4,2,3,4,2];
    const result = [...new Set(arr)];
    console.log(result);
    
        30
  •  2
  •   Community Ramakrishna.p    7 年前

    也可以使用jquery

    var a = [1,5,1,6,4,5,2,5,4,3,1,2,6,6,3,3,2,4];
    
    // note: jQuery's filter params are opposite of javascript's native implementation :(
    var unique = $.makeArray($(a).filter(function(i,itm){ 
        // note: 'index', not 'indexOf'
        return i == $(a).index(itm);
    }));
    
    // unique: [1, 5, 6, 4, 2, 3]
    

    最初回答时间: jQuery function to get all unique elements from an array?