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

2020/09/16 11:02 · javascript ·  · 0评论

我需要确定一个唯一的数字数组。我在互联网上找到了下面的代码片段,并且在数组中包含零之前,它都可以正常工作。在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;
}

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

类似的问题:

使用JavaScript 1.6 / ECMAScript 5,您可以通过filter以下方式使用Array 的本机方法来获取具有唯一值的数组:

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)即可工作。

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

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

如果你想保持一个值的最后出现,简单的更换indexOflastIndexOf

使用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),并且散布运算符...将集合转换回Array。感谢Lukas Liese的评论提示。

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所建议的那样,也可以使用传播算子来缩短它,例如

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

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

  1. 使用对象{ }防止重复
  2. 使用辅助数组 [ ]
  3. filter + indexOf
  4. 奖金!ES6 Sets方法。

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

使用对象{ }防止重复

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

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

使用ES6 [...new Set(a)]

function uniqueArray4(a) {
  return [...new Set(a)];
}

我想知道哪一个更快。我制作了示例Google表格来测试功能。注意:ECMA 6在Google表格中不可用,因此我无法对其进行测试。

测试结果如下:
在此处输入图片说明

我希望看到使用object的代码{ }会赢,因为它使用了hash。因此,我很高兴测试显示该算法在Chrome和IE中效果最佳。感谢@rab提供的代码

更新2020

启用了Google脚本的ES6引擎。现在,我使用来测试最后一个代码,Sets它的出现速度比对象方法快。

您还可以使用underscore.js

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

它将返回:

[1, 2, 3, 4]

一线纯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 +

从那以后,我发现了一个使用jQuery的不错的方法

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

注意:此代码是从Paul Irish的鸭打孔帖子中提取 -我忘了给您以荣誉

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

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

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

EcmaScript 6 目前(2015年8月)在现代浏览器中部分实现,但是Babel在将ES6(甚至是ES7)转换回ES5方面变得非常流行。这样,您就可以立即编写ES6代码!

如果您想知道这是什么...意思,那就叫价差算子MDN中:“扩展运算符允许在需要多个参数(用于函数调用)或多个元素(用于数组文字)的地方扩展表达式”。因为Set是可迭代的(并且只能具有唯一值),所以散布运算符将扩展Set来填充数组。

学习ES6的资源:

最简单的解决方案:

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

最简单,最快的方法(在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的说法,此功能是我在任何地方都能找到的最快的功能-随时添加自己的功能。

非原型版本:

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浏览器中,这也比上述方法快

仅性能!此代码可能比此处的所有代码快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--循环。除了我们都非常喜欢的浏览器外,Chrome浏览器是所有浏览器中最快的循环。

无论如何,我编写了第一个使用while的函数,是的,它比本文中找到的函数要快一点,但还不够。unique2()

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

在这一点上,我正在考虑自己真正需要的功能。我不需要旧的数组,我想要一个快速的函数。所以我用了2个while循环+拼接。unique4()

没用说我印象深刻。

chrome: the usual 150,000 operations per second jumped to 1,800,000 operations per second.

ie: 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 or better use console.time... microtime... whatever

unique5() is just to show you what happens if you want to keep the old array.

Don't use Array.prototype if yu don't know what your doing.
i just did alot of copy and past.
Use Object.defineProperty(Array.prototype,...,writable:false,enumerable:false}) if you want to create a native prototype.example: 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); 

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

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

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

Array.from到重新设置为一个数组转换,这样你可以很方便地访问所有的真棒方法(特征),数组必须是有用的。还有其他做相同事情的方法。但是您可能根本不需要Array.from,因为Set具有很多有用的功能,例如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)部分将成为我们命名为结果的东西

只需将您喜欢的任何数组的名称传递给它即可。

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

我们可以使用ES6集来做到这一点:

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

console.log(uniqueArray);

//输出将是

uniqueArray = [1,2,3,4,5];

这个原型getUnique不是完全正确的,因为如果我有一个类似Array的东西:["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"]

无需扩展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 Store App,Firefox OS,Sencha,Phonegap,Titanium等)的开发非常有用。

[...new Set(duplicates)]

这是最简单的方法,可从MDN Web Docs中引用

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]

魔法

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

O(n) 性能我们假设您的数组位于a和中t={}此处说明(+ 杰普展示)

如果您使用的是Prototype框架,则无需执行“ for”循环,可以使用http://www.prototypejs.org/api/array/uniq这样:

var a = Array.uniq();  

这将产生一个没有重复的重复数组。我遇到了您的问题,寻找一种计算不同数组记录的方法,因此

uniq()

我用了

尺寸()

结果很简单。ps对不起,如果我输错了一些内容

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

紧凑()

之前,像这样:

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

现在,使用集,您可以删除重复项并将其转换回数组。

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

那是因为这0是JavaScript中的虚假值。

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

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
}

我有一个稍微不同的问题,我需要从数组中删除具有重复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);

最简单的答案是:

const array = [1, 1, 2, 2, 3, 5, 5, 2];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 5]

来自Shamasis Bhattacharya的博客(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的博客:对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]

这已经得到了很多回答,但是并没有解决我的特殊需求。

许多答案是这样的:

a.filter((item, pos, self) => self.indexOf(item) === pos);

但这不适用于复杂对象的数组。

说我们有一个像这样的数组:

const a = [
 { age: 4, name: 'fluffy' },
 { age: 5, name: 'spot' },
 { age: 2, name: 'fluffy' },
 { age: 3, name: 'toby' },
];

如果我们想要具有唯一名称的对象,则应使用array.prototype.findIndex而不是array.prototype.indexOf

a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);

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

如果您对额外的依赖关系没问题,或者您的代码库中已有一个库,则可以使用LoDash(或Underscore)从适当的位置删除数组中的重复项。

用法

如果您的代码库中还没有它,请使用npm进行安装:

npm install lodash

然后按如下方式使用它:

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

出:

[ 1, 2, 3 ]

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

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]

奇怪的是以前没有建议过..要通过id数组中的对象键(下面)删除重复项,您可以执行以下操作:

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

看来我们已经失去了拉斐尔(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;
}
本文地址:http://javascript.askforanswer.com/huoqujavascriptshuzuzhongdesuoyouweiyizhishanchuzhongfuxiang.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!