获取数组中的所有唯一值(删除重复项)
我有一系列的数字,我需要确保是唯一的。 我在互联网上find了下面的代码片段,直到数组中有一个零为止。 我在这里发现了这个其他的脚本 ,看起来几乎完全一样,但它并没有失败。
所以为了帮助我学习,有人能帮我确定原型脚本出错的地方吗?
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数组中删除重复项
类似的问题:
- 在一个数组中获得具有多个出现(即:不唯一)的所有值
使用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
将循环访问数组,只保留那些通过给定callback函数onlyUnique
。
onlyUnique
检查,如果给定的值是第一次发生。 如果不是,它必须是重复的,不会被复制。
这个解决scheme没有任何额外的库,如jQuery或prototype.js。
它也适用于具有混合值types的数组。
对于不支持本地方法filter
和indexOf
旧浏览器(<ie9),您可以在MDN文档中find有关filter和indexOf的变通办法。
如果要保留最后一次出现的值,可以简单地用lastIndexOf
replaceindexOf
。
用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,并且spread操作符将这个集合转换回Array。 感谢Lukas Liese提供的意见。
更新了ES6 / ES2015的答案 :使用Set ,单线解决scheme是:
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_mbuild议的那样,这也可以使用扩展运算符来缩短,就像
var uniqueItems = [...new Set(items)]
你也可以使用underscore.js 。
console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="underscore-min.js"></script>
我意识到这个问题已经有30多个答案了。 但是我已经通读了所有现有的答案,并做了我自己的研究。
我将所有答案分为4个可能的解决scheme:
- 使用新的ES6function:
[...new Set( [1, 1, 2] )];
1,1,2[...new Set( [1, 1, 2] )];
- 使用对象
{ }
来防止重复 - 使用帮助者数组
[ ]
- 使用
filter + indexOf
以下是答案中的示例代码:
使用新的ES6function: [...new Set( [1, 1, 2] )];
1,1,2 [...new Set( [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; }
使用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; }
我想知道哪一个更快。 我已经制作了Google Sheet的示例来testing函数。 注意:ECMA 6在Google表格中不可用,所以我无法对其进行testing。
这是testing的结果:
我期望看到使用object { }
代码会赢,因为它使用散列。 所以我很高兴testing在Chrome和IE中显示了这个algorithm的最佳结果。 感谢@rab 的代码 。
我从那以后find了一个使用jQuery的好方法
arr = $.grep(arr, function(v, k){ return $.inArray(v ,arr) === k; });
注意:这段代码是从保罗·爱尔兰的鸭子哨子里拉出来的 – 我忘了给信用:P
使用ES6的最短解决scheme: [...new Set( [1, 1, 2] )];
1,1,2 [...new Set( [1, 1, 2] )];
或者如果你想修改数组的原型(就像在原来的问题):
Array.prototype.getUnique = function() { return [...new Set( [this] )]; };
目前(2015年8月),EcmaScript 6仅部分在现代浏览器中实现 ,但Babel已经非常stream行,将ES6(甚至ES7)转换回ES5。 这样你可以写今天的ES6代码!
如果你想知道什么...
意思,这就是所谓的传播运算符 。 从MDN开始 :«扩展运算符允许expression式在需要多个参数(用于函数调用)或多个元素(用于数组文字)的地方扩展。 因为一个Set是一个可迭代的(并且只能有唯一的值),所以spread操作符将展开Set来填充数组。
学习资源ES6:
- 由Axel Rauschmayer博士探索ES6
- 从JS每周通讯中search“ES6”
- ES6深入 Mozilla黑客博客文章
一个class轮,纯粹的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 +
最简单的解决scheme
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1]; console.log([...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; }
简单地遍历数组中的每个项目,testing该项目是否已经在列表中,如果不是,则推送到返回的数组。
根据jsPerf的说法,这个函数是我能find的最快的函数 – 尽pipe可以自由添加。
非原型版本:
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; }
sorting
当还需要对数组进行sorting时,以下是最快的:
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]
这里的许多答案可能对初学者没有用处。 如果重复数组是困难的,他们真的会知道原型链,甚至jQuery吗?
在现代浏览器中,一个干净而简单的解决scheme是将数据存储在一个Set中 ,该Set被devise成一个唯一值列表。
const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford']; const uniqueCars = Array.from(new Set(cars));
Array.from
对于将Set转换回Array是很有用的,这样你就可以轻松访问数组所拥有的所有真棒方法(特性)。 还有其他方式做同样的事情。 但是你可能根本不需要Array.from
,因为Sets有许多有用的function,比如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 // - aka 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)
部分成为我们在函数完成时命名的结果 。
只要通过它你喜欢的任何数组的名称。
这个getUnique
原型是不完全正确的,因为如果我有一个数组如: ["1",1,2,3,4,1,"foo"]
它将返回["1","2","3","4"]
和"1"
是string, 1
是整数; 他们是不同的。
这是一个正确的解决scheme:
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"]
。
["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; }, []);
不扩展Array.prototype(据说这是一个不好的做法)或使用jQuery /下划线,你可以简单地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(Windowsapp store应用程序,Firefox操作系统,Sencha,Phonegap,titanium,…)的发展很好。
这是因为0
是JavaScript中的一个虚假值。
如果数组的值为0或任何其他falsy值, this[i]
将是虚假的。
如果使用Prototype框架,则不需要执行for循环,可以像这样使用http://www.prototypejs.org/api/array/uniq :
var a = Array.uniq();
这将产生一个没有重复的重复数组。 我碰到你的问题search一个方法来计算不同的数组logging
uniq的()
我用了
尺寸()
有我简单的结果。 ps对不起,如果我misstyped的东西
编辑:如果你想逃避未定义的logging,你可能想添加
紧凑()
之前,像这样:
var a = Array.compact().uniq();
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 }
我不确定为什么加布里埃尔·西尔维拉(Gabriel Silveira)这样写这个函数,而是一个简单的forms,对我来说也是一样的,没有缩小就是:
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 )
来自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]
在简单的方法中find唯一的数组值
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]
反过来解决这个问题,在加载数组的时候可能没有重复, 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]
你也可以使用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函数从数组中获取所有独特的元素?
如果有人使用knockoutjs
ko.utils.arrayGetDistinctValues()
顺便说一句,看看所有的ko.utils.array*
工具。
我发现序列化他们的哈希键帮助我得到这个对象的工作。
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; }
你也可以使用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"}]
这将工作。
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; }
build立在其他的答案,这里是另一个变种,采取一个可选的标志来select一个策略(保持第一次发生或保持最后):
不扩展 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]
扩展 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]
Using object keys to make unique array, I have tried following
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]);
Which returns ["1", 1, 2, 3, 4, "foo", false, null]
Look at this. Jquery provides uniq method: https://api.jquery.com/jQuery.unique/
var ids_array = [] $.each($(my_elements), function(index, el) { var id = $(this).attr("id") ids_array.push(id) }); var clean_ids_array = jQuery.unique(ids_array) $.each(clean_ids_array, function(index, id) { elment = $("#" + id) // my uniq element // TODO WITH MY ELEMENT });
If you have the mighty reduce method available ( ≥ 5.1 ), you can try something like this:
Array.prototype.uniq = function() { return this.reduce(function(sofar, cur) { return sofar.indexOf(cur) < 0 ? sofar.concat([cur]) : sofar; }, []); };
It's not the most efficient implementation (because of the indexOf
check, which may in the worst case go through the entire list). If efficiency matters, you can keep the "history" of occurrences in some random-access structure (say, {}
) and key those instead. That's basically what the most voted answer does, so check that out for an example.