首页 文章

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

提问于
浏览
920

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

来自重复提问的更多答案:

同类的问题:

30 回答

  • 100

    我们可以使用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];
    
  • 29

    我发现序列化他们的哈希键帮助我实现了对象的工作 .

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

    你也可以使用underscore.js .

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

    将返回:

    [1, 2, 3, 4]
    
  • 2

    我后来发现了一个使用jQuery的好方法

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

    注意:此代码是从Paul Irish's duck punching post中提取的 - 我忘了给予赞誉:P

  • 12

    以简单的方法查找唯一的Array值

    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]
    
  • 31

    如果有人使用knockoutjs

    ko.utils.arrayGetDistinctValues()
    

    BTW已经查看了所有 ko.utils.array* 实用程序 .

  • 6

    要反过来解决这个问题,在加载数组时没有重复可能会很有用,Set对象会这样做,但它还没有在所有浏览器中都可用 . 如果您需要多次查看其内容,它可以节省内存并提高效率 .

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

    样品:

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

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

  • 5

    如果你为'循环,你可以像这样使用http://www.prototypejs.org/api/array/uniq

    var a = Array.uniq();
    

    这将生成一个没有重复的重复数组 . 我遇到了一个问题,搜索一个方法来计算不同的数组记录

    uniq()

    我用了

    size()

    这是我的简单结果 . 附:对不起,如果我错误的输入了什么

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

    紧凑()

    之前,像这样:

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

    奇怪的是之前没有建议..要删除数组中的对象键(下面的 id )重复项,你可以这样做:

    const uniqArray = array.filter((obj, idx, arr) => (
      arr.findIndex((o) => o.id === obj.id) === idx
    ))
    
  • 2

    如果没有扩展Array.prototype(它被认为是一种不好的做法)或使用jquery / underscore,你可以简单地 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;
            });
        },
    

    好吧,它只是javascript ECMAScript 5,这意味着只有IE9,但它适用于原生HTML / JS(Windows应用商店应用,Firefox OS,Sencha,Phonegap,Titanium等)的开发 .

  • 1709

    最简单的解决方案

    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)));
    
  • 590

    使用对象键来制作独特的数组,我试过以下

    function uniqueArray( ar ) {
      var j = {};
    
      ar.forEach( function(v) {
        j[v+ '::' + typeof v] = v;
      });
    
    
      return Object.keys(j).map(function(v){
        return j[v];
      });
    }   
    
    uniqueArray(["1",1,2,3,4,1,"foo", false, false, null,1]);
    

    返回 ["1", 1, 2, 3, 4, "foo", false, null]

  • 9

    使用JavaScript 1.6 / ECMAScript 5,您可以通过以下方式使用Array的本机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']
    

    本机方法 filter 将遍历数组并仅保留那些通过给定回调函数 onlyUnique 的条目 .

    onlyUnique 检查,如果给定的值是第一次发生 . 如果没有,则必须是重复的,不会被复制 .

    此解决方案无需任何额外的库,如jQuery或prototype.js .

    它适用于具有混合值类型的数组 .

    对于不支持本机方法 filterindexOf 的旧浏览器(<ie9),您可以在filterindexOf的MDN文档中找到解决方法 .

    如果要保留最后一次出现的值,请简单地将 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']
    

    Set 的构造函数采用可迭代对象(如Array),并且扩展运算符 ... 将该集转换回数组 . 感谢Lukas Liese提示评论 .

  • 2
    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
    }
    
  • 6

    你也可以使用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?

  • 6

    我意识到这个问题已有30多个答案 . 但我先阅读了所有现有的答案并进行了自己的研究 .

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

    • 使用新的ES6功能: [...new Set( [1, 1, 2] )];

    • 使用对象 { } 来防止重复

    • 使用辅助数组 [ ]

    • 使用 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;
    }
    

    使用过滤器indexOf

    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在Google表格中不可用,因此我无法对其进行测试 .

    这是测试的结果:

    我希望看到使用对象 { } 的代码将获胜,因为它使用哈希 . 所以我很高兴测试在Chrome和IE中显示了该算法的最佳结果 . 感谢@rab for the code .

  • 8

    这里的许多答案可能对初学者没用 . 如果难以对数组进行重复数据删除,他们真的会知道原型链,甚至是jQuery吗?

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

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

    Array.from 对于将Set转换回Array非常有用,这样您就可以轻松访问数组所具有的所有令人敬畏的方法(功能) . 还有other ways做同样的事情 . 但是你可能根本不需要 Array.from ,因为集合有很多有用的功能,如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) 部分 becomes 我们在函数完成时命名的结果 .

    只需传递你喜欢的任何数组的名称 .

  • 49

    那是因为 0 是JavaScript中的虚假值 .

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

  • 17

    One Liner,Pure JavaScript

    With ES6 syntax

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

    With ES5 syntax

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

    Browser Compatibility :IE9

  • 16
    ["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;
     }, []);
    
  • 9

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

  • 44

    这会奏效 .

    function getUnique(a) {
      var b = [a[0]], i, j, tmp;
      for (i = 1; i < a.length; i++) {
        tmp = 1;
        for (j = 0; j < b.length; j++) {
          if (a[i] == b[j]) {
            tmp = 0;
            break;
          }
        }
        if (tmp) {
          b.push(a[i]);
        }
      }
      return b;
    }
    
  • 5

    PERFORMANCE ONLY! this code is probably 10X faster than all the codes in here *适用于所有浏览器,并且内存影响最小....等等

    如果你不需要重用旧的数组;顺便说一句,在你将它转换为唯一之前做必要的其他操作,这可能是最快的方法,也很短 .

    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--循环 . 虽然是所有浏览器中最快的循环,除了我们都非常喜欢的那个... chrome .

    无论如何我写了第一个使用while的函数 . 是的,它比文章中的函数快一点 . 但还不够 . unique2()

    下一步使用现代js . Object.keys 我用js1.7的Object.keys替换了另一个for循环...更快更短(在chrome中快了2倍);) . 不够! . unique3() .

    在这一点上,我正在思考我在我独特功能中真正需要的东西 . 我不需要旧的阵列,我想要一个快速的功能 . 所以我使用2 while循环拼接 . unique4()

    Useless to say that i was impressed.

    chrome:通常每秒150,000次操作跃升至每秒1,800,000次操作 .

    即:80,000 op / s vs 3,500,000 op / s

    ios:18,000 op / s vs 170,000 op / s

    safari: 80,000 op/s vs 6,000,000 op/s

    Proof http://jsperf.com/wgu或更好地使用console.time ... microtime ......无论如何

    unique5() 只是为了告诉你如果要保留旧数组会发生什么 .

    如果你不知道你在做什么,请不要使用 Array.prototype . 我刚做了很多副本和过去 . 如果要创建本机prototype.example,请使用 Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})https://stackoverflow.com/a/20463021/2450730

    Demo http://jsfiddle.net/46S7g/

    NOTE: your old array is destroyed/becomestheunique after this operation.

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

    有些人正在使用 indexOf ...不要...... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

    对于空数组

    !array.length||toUnique(array);
    
  • 3

    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]
    
  • 10

    你也可以用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"}]
    
  • 2

    Updated answer for 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]
    

    正如le_m建议的那样,这也可以使用spread operator缩短,就像

    var uniqueItems = [...new Set(items)]
    
  • 3

    最简单的,以及在Chrome中执行此操作的方式:

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

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

    根据jsPerf,这个函数是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;
    }
    

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

  • 120

    我不确定为什么加布里埃尔·西尔维拉(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
      )
    
  • 32

    在其他答案的基础上,这是另一个变量,它采用可选标志来选择策略(保持第一次出现或保持最后):

    Without extending Array.prototype

    function unique(arr, keepLast) {
      return arr.filter(function (value, index, array) {
        return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
      });
    };
    
    // Usage
    unique(['a', 1, 2, '1', 1, 3, 2, 6]); // -> ['a', 1, 2, '1', 3, 6]
    unique(['a', 1, 2, '1', 1, 3, 2, 6], true); // -> ['a', '1', 1, 3, 2, 6]
    

    Extending Array.prototype

    Array.prototype.unique = function (keepLast) {
      return this.filter(function (value, index, array) {
        return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
      });
    };
    
    // Usage
    ['a', 1, 2, '1', 1, 3, 2, 6].unique(); // -> ['a', 1, 2, '1', 3, 6]
    ['a', 1, 2, '1', 1, 3, 2, 6].unique(true); // -> ['a', '1', 1, 3, 2, 6]
    
  • 3

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

    或者,如果要修改Array原型(如原始问题中所示):

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

    目前(2015年8月),现代浏览器中的EcmaScript 6仅为partially implemented,但是Babel已经变得非常受欢迎将ES6(甚至是ES7)转发回ES5 . 这样你今天就可以编写ES6代码了!

    如果你想知道 ... 的意思,它叫做spread operator . 从MDN:«扩展运算符允许在多个参数(用于函数调用)或多个元素(用于数组文字)的位置扩展表达式» . 因为Set是可迭代的(并且只能具有唯一值),所以扩展运算符将展开Set以填充数组 .

    学习ES6的资源:

    由Axel Rauschmayer博士撰写的

相关问题