从JS数组中删除重复值

我有一个非常简单的JavaScript数组,可能包含也可能不包含重复项。

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

我需要删除重复项并将唯一值放入新数组中。

我可以指出我尝试过的所有代码,但我认为这是无用的,因为它们不起作用。我也接受jQuery解决方案。

类似问题:

2726766 次浏览

Vanilla JS:使用像Set这样的对象删除重复项

你总是可以尝试将它放入一个对象中,然后遍历它的键:

function remove_duplicates(arr) {var obj = {};var ret_arr = [];for (var i = 0; i < arr.length; i++) {obj[arr[i]] = true;}for (var key in obj) {ret_arr.push(key);}return ret_arr;}

Vanilla JS:通过跟踪已经看到的值来删除重复项(订单安全)

或者,对于订单安全版本,使用对象存储所有以前看到的值,并在添加到数组之前检查它的值。

function remove_duplicates_safe(arr) {var seen = {};var ret_arr = [];for (var i = 0; i < arr.length; i++) {if (!(arr[i] in seen)) {ret_arr.push(arr[i]);seen[arr[i]] = true;}}return ret_arr;
}

ECMAScript 6:使用新的Set数据结构(订单安全)

ECMAScript 6添加了新的Set数据结构,它允许您存储任何类型的值。Set.values按插入顺序返回元素。

function remove_duplicates_es6(arr) {let s = new Set(arr);let it = s.values();return Array.from(it);}

示例用法:

a = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
b = remove_duplicates(a);// b:// ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]
c = remove_duplicates_safe(a);// c:// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]
d = remove_duplicates_es6(a);// d:// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

太长别读

使用设置构造函数和扩展语法

uniq = [...new Set(array)];

“聪明”但天真的方式

uniqueArray = a.filter(function(item, pos) {return a.indexOf(item) == pos;})

基本上,我们遍历数组,并针对每个元素检查该元素在数组中的第一个位置是否等于当前位置。显然,这两个位置对于重复元素是不同的。

使用过滤器回调的第三个(“this数组”)参数,我们可以避免数组变量的闭包:

uniqueArray = a.filter(function(item, pos, self) {return self.indexOf(item) == pos;})

虽然简洁,但该算法对于大型数组(二次时间)并不特别有效。

哈希表救援

function uniq(a) {var seen = {};return a.filter(function(item) {return seen.hasOwnProperty(item) ? false : (seen[item] = true);});}

通常是这样做的。这个想法是将每个元素放在哈希表中,然后立即检查它的存在。这给了我们线性时间,但至少有两个缺点:

  • 由于哈希键在JavaScript中只能是字符串或符号,因此此代码无法区分数字和“数字字符串”。也就是说,uniq([1,"1"])将只返回[1]
  • 出于同样的原因,所有对象都将被视为相等:uniq([{foo:1},{foo:2}])将仅返回[{foo:1}]

也就是说,如果您的数组只包含原语并且您不关心类型(例如它总是数字),则此解决方案是最佳的。

两个世界最好的

通用解决方案结合了这两种方法:它使用哈希查找原语和线性搜索对象。

function uniq(a) {var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];
return a.filter(function(item) {var type = typeof item;if(type in prims)return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);elsereturn objs.indexOf(item) >= 0 ? false : objs.push(item);});}

排序|uniq

另一种选择是先对数组进行排序,然后删除每个等于前一个的元素:

function uniq(a) {return a.sort().filter(function(item, pos, ary) {return !pos || item != ary[pos - 1];});}

同样,这不适用于对象(因为所有对象对于sort都相等)。此外,我们默默地更改原始数组作为副作用-不好!但是,如果您的输入已经排序,这是要走的路(只需从上面删除sort)。

独特的…

有时需要基于除相等之外的其他条件统一列表,例如,过滤掉不同但共享一些属性的对象。这可以通过传递回调来优雅地完成。这个“key”回调应用于每个元素,具有相等“key”的元素被删除。由于key预计将返回一个基元,哈希表在这里可以正常工作:

function uniqBy(a, key) {var seen = {};return a.filter(function(item) {var k = key(item);return seen.hasOwnProperty(k) ? false : (seen[k] = true);})}

一个特别有用的key()JSON.stringify,它将删除物理上不同但“看起来”相同的对象:

a = [[1,2,3], [4,5,6], [1,2,3]]b = uniqBy(a, JSON.stringify)console.log(b) // [[1,2,3], [4,5,6]]

如果key不是原始的,你必须求助于线性搜索:

function uniqBy(a, key) {var index = [];return a.filter(function (item) {var k = key(item);return index.indexOf(k) >= 0 ? false : index.push(k);});}

在ES6中,您可以使用Set

function uniqBy(a, key) {let seen = new Set();return a.filter(item => {let k = key(item);return seen.has(k) ? false : seen.add(k);});}

Map

function uniqBy(a, key) {return [...new Map(a.map(x => [key(x), x])).values()]}

它们都可以用于非原始键。

第一个还是最后一个?

通过键删除对象时,您可能希望保留“相等”对象中的第一个或最后一个。

使用上面的Set变体保留第一个,使用Map保留最后一个:

function uniqByKeepFirst(a, key) {let seen = new Set();return a.filter(item => {let k = key(item);return seen.has(k) ? false : seen.add(k);});}

function uniqByKeepLast(a, key) {return [...new Map(a.map(x => [key(x), x])).values()]}
//
data = [{a:1, u:1},{a:2, u:2},{a:3, u:3},{a:4, u:1},{a:5, u:2},{a:6, u:3},];
console.log(uniqByKeepFirst(data, it => it.u))console.log(uniqByKeepLast(data, it => it.u))

图书馆

强调Lo-Dash都提供了uniq方法。它们的算法基本上类似于上面的第一个片段,归结为:

var result = [];a.forEach(function(item) {if(result.indexOf(item) < 0) {result.push(item);}});

这是二次的,但也有很好的附加好处,比如包装原生indexOf,通过键(用他们的说法是iteratee)统一的能力,以及对已经排序的数组的优化。

如果你正在使用jQuery并且无法忍受任何没有美元的东西,它是这样的:

  $.uniqArray = function(a) {return $.grep(a, function(item, pos) {return $.inArray(item, a) === pos;});}

这也是第一个片段的变体。

性能

函数调用在JavaScript中是昂贵的,因此上述解决方案尽管简洁,但并不是特别有效。为了获得最大的性能,请将filter替换为循环并摆脱其他函数调用:

function uniq_fast(a) {var seen = {};var out = [];var len = a.length;var j = 0;for(var i = 0; i < len; i++) {var item = a[i];if(seen[item] !== 1) {seen[item] = 1;out[j++] = item;}}return out;}

这段丑陋的代码与上面的片段#3但要快一个数量级相同(截至2017年,它的速度只有两倍-JS核心人员做得很好!)

function uniq(a) {var seen = {};return a.filter(function(item) {return seen.hasOwnProperty(item) ? false : (seen[item] = true);});}
function uniq_fast(a) {var seen = {};var out = [];var len = a.length;var j = 0;for(var i = 0; i < len; i++) {var item = a[i];if(seen[item] !== 1) {seen[item] = 1;out[j++] = item;}}return out;}
/////
var r = [0,1,2,3,4,5,6,7,8,9],a = [],LEN = 1000,LOOPS = 1000;
while(LEN--)a = a.concat(r);
var d = new Date();for(var i = 0; i < LOOPS; i++)uniq(a);document.write('<br>uniq, ms/loop: ' + (new Date() - d)/LOOPS)
var d = new Date();for(var i = 0; i < LOOPS; i++)uniq_fast(a);document.write('<br>uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6

ES6提供了设置对象,这使事情变得容易得多:

function uniq(a) {return Array.from(new Set(a));}

let uniq = a => [...new Set(a)];

请注意,与python不同,ES6集合是按插入顺序迭代的,因此此代码保留了原始数组的顺序。

但是,如果您需要一个具有唯一元素的数组,为什么不从一开始就使用集合呢?

发电机

可以在相同的基础上构建uniq的“懒惰”、基于生成器的版本:

  • 从参数中获取下一个值
  • 如果已经看过了就跳过
  • 否则,产生它并将其添加到一组已经看到的值

function* uniqIter(a) {let seen = new Set();
for (let x of a) {if (!seen.has(x)) {seen.add(x);yield x;}}}
// example:
function* randomsBelow(limit) {while (1)yield Math.floor(Math.random() * limit);}
// note that randomsBelow is endless
count = 20;limit = 30;
for (let r of uniqIter(randomsBelow(limit))) {console.log(r);if (--count === 0)break}
// exercise for the reader: what happens if we set `limit` less than `count` and why

使用jQuery快速而脏:

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];var uniqueNames = [];$.each(names, function(i, el){if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);});

使用Underscore.js

它是一个库,其中包含许多用于操作数组的函数。

这是与jQuery的燕尾服搭配的领带,Backbone.js吊带。

_. uniq

_.uniq(array, [isSorted], [iterator])别名:独特
生成阵列的无重复版本,使用===来测试对象相等。如果您事先知道阵列已排序,则传递真正 forisSorted将运行更快的算法。如果你想基于转换计算唯一项,传递迭代器函数。

示例

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
alert(_.uniq(names, false));

注意:LO-Dash(一个下划线竞争者)也提供了类似的. uniq

以下方法比列出的jQuery方法快80%以上(请参阅下面的测试)。这是几年前一个类似问题的答案。如果我遇到最初提出这个问题的人,我会发布信用。纯JS。

var temp = {};for (var i = 0; i < array.length; i++)temp[array[i]] = true;var r = [];for (var k in temp)r.push(k);return r;

我的测试用例比较:http://jsperf.com/remove-duplicate-array-tests

这是另一种使用jQuery的方法,

function uniqueArray(array){if ($.isArray(array)){var dupes = {}; var len, i;for (i=0,len=array.length;i<len;i++){var test = array[i].toString();if (dupes[test]) { array.splice(i,1); len--; i--; } else { dupes[test] = true; }}}else {if (window.console) console.log('Not passing an array to uniqueArray, returning whatever you sent it - not filtered!');return(array);}return(array);}

作者:威廉·斯基德莫尔

function removeDuplicates(inputArray) {var outputArray=new Array();
if(inputArray.length>0){jQuery.each(inputArray, function(index, value) {if(jQuery.inArray(value, outputArray) == -1){outputArray.push(value);}});}return outputArray;}

上面的答案的复杂度为O(n²),但这可以通过使用对象作为哈希来仅使用O(n)来完成:

function getDistinctArray(arr) {var dups = {};return arr.filter(function(el) {var hash = el.valueOf();var isDup = dups[hash];dups[hash] = true;return !isDup;});}

这适用于字符串、数字和日期。如果您的数组包含对象,上述解决方案将不起作用,因为当强制转换为字符串时,它们都将具有"[object Object]"(或类似的值)的值,并且不适合作为查找值。您可以通过在对象本身设置标志来获得对象的O(n)实现:

function getDistinctObjArray(arr) {var distinctArr = arr.filter(function(el) {var isDup = el.inArray;el.inArray = true;return !isDup;});distinctArr.forEach(function(el) {delete el.inArray;});return distinctArr;}

2019编辑:现代版本的JavaScript使这个问题更容易解决。使用Set将有效,无论您的数组是否包含对象、字符串、数字或任何其他类型。

function getDistinctArray(arr) {return [...new Set(arr)];}

实现非常简单,不再需要定义函数。

使用数组.filter.indexOf函数的单行版本:

arr = arr.filter(function (value, index, array) {return array.indexOf(value) === index;});

如果你不想包含整个库,你可以使用这个来添加任何数组都可以使用的方法:

Array.prototype.uniq = function uniq() {return this.reduce(function(accum, cur) {if (accum.indexOf(cur) === -1) accum.push(cur);return accum;}, [] );}
["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"].uniq()

如果您自己创建数组,您可以在插入数据时进行检查,从而为自己节省一个循环和额外的唯一过滤器;

var values = [];$.each(collection, function() {var x = $(this).value;if (!$.inArray(x, values)) {values.push(x);}});

厌倦了用for-loops或jQuery看到所有糟糕的例子。Javascript现在有完美的工具:排序、映射和缩减。

Uniq减少,同时保持现有订单

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniq = names.reduce(function(a,b){if (a.indexOf(b) < 0 ) a.push(b);return a;},[]);
console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]
// one linerreturn names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);

更快的uniq排序

可能有更快的方法,但这种方法相当不错。

var uniq = names.slice() // slice makes copy of array before sorting it.sort(function(a,b){return a > b;}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b); // slice(-1)[0] means last item in array without removing it (like .pop())return a;},[]); // this empty array becomes the starting value for a
// one linerreturn names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b);return a;},[]);

2015年更新:ES6版本:

在ES6中,你有设置和传播,这使得删除所有重复项变得非常容易和高效:

var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

基于发生的排序:

有人询问根据有多少个唯一名称对结果进行排序:

var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']
var uniq = names.map((name) => {return {count: 1, name: name}}).reduce((a, b) => {a[b.name] = (a[b.name] || 0) + b.countreturn a}, {})
var sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b])
console.log(sorted)

稍微修改了thg435的优秀答案,使用自定义比较器:

function contains(array, obj) {for (var i = 0; i < array.length; i++) {if (isEqual(array[i], obj)) return true;}return false;}//comparatorfunction isEqual(obj1, obj2) {if (obj1.name == obj2.name) return true;return false;}function removeDuplicates(ary) {var arr = [];return ary.filter(function(x) {return !contains(arr, x) && arr.push(x);});}
$(document).ready(function() {
var arr1=["dog","dog","fish","cat","cat","fish","apple","orange"]
var arr2=["cat","fish","mango","apple"]
var uniquevalue=[];var seconduniquevalue=[];var finalarray=[];
$.each(arr1,function(key,value){
if($.inArray (value,uniquevalue) === -1){uniquevalue.push(value)
}
});
$.each(arr2,function(key,value){
if($.inArray (value,seconduniquevalue) === -1){seconduniquevalue.push(value)
}
});
$.each(uniquevalue,function(ikey,ivalue){
$.each(seconduniquevalue,function(ukey,uvalue){
if( ivalue == uvalue)
{finalarray.push(ivalue);}
});
});alert(finalarray);});

这可能是从数组中永久删除重复项的最快方法之一比这里的大多数功能快10倍。在Safari中快78倍

function toUnique(a,b,c){               //array,placeholder,placeholderb=a.length;while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1)}
  1. 测试:http://jsperf.com/wgu
  2. 演示:http://jsfiddle.net/46S7g/
  3. 更多:https://stackoverflow.com/a/25082874/2450730

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

另一种无需编写太多代码即可完成此操作的方法是使用ES5Object.keys-方法:

var arrayWithDuplicates = ['a','b','c','d','a','c'],deduper = {};arrayWithDuplicates.forEach(function (item) {deduper[item] = null;});var dedupedArray = Object.keys(deduper); // ["a", "b", "c", "d"]

在函数中抽取

function removeDuplicates (arr) {var deduper = {}arr.forEach(function (item) {deduper[item] = null;});return Object.keys(deduper);}

以下是对这个问题的简单回答。

var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"];var uniqueNames = [];
for(var i in names){if(uniqueNames.indexOf(names[i]) === -1){uniqueNames.push(names[i]);}}

在ECMAScript 6(又名ECMAScript 2015)中,#0可用于过滤掉重复项。然后可以使用点差算子将其转换回数组。

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"],unique = [...new Set(names)];

删除字符串重复的最简单方法是使用关联数组,然后遍历关联数组以使列表/数组返回。

像下面这样:

var toHash = [];var toList = [];
// add from ur data list to hash$(data.pointsToList).each(function(index, Element) {toHash[Element.nameTo]= Element.nameTo;});
// now convert hash to array// don't forget the "hasownproperty" else u will get random resultsfor (var key in toHash)  {if (toHash.hasOwnProperty(key)) {toList.push(toHash[key]);}}

瞧,现在副本不见了!

删除重复的最简单方法是执行for循环并比较不相同的元素并将它们推送到新数组中

 var array = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var removeDublicate = function(arr){var result = []var sort_arr = arr.sort() //=> optionalfor (var i = 0; i < arr.length; i++) {if(arr[ i + 1] !== arr[i] ){result.push(arr[i])}};return result}console.log(removeDublicate(array))==>  ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]

去这一个:

var uniqueArray = duplicateArray.filter(function(elem, pos) {return duplicateArray.indexOf(elem) == pos;});

现在uniqueArray不包含重复项。

以下脚本返回一个仅包含唯一值的新数组。它适用于字符串和数字。不需要额外的库,只需vanilla JS。

浏览器支持:

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

https://jsfiddle.net/fzmcgcxv/3/

var duplicates = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl","Mike","Mike","Nancy","Carl"];var unique = duplicates.filter(function(elem, pos) {return duplicates.indexOf(elem) == pos;});alert(unique);

我知道我有点晚了,但这里有另一个使用jinqJs的选项

见小提琴

var result = jinqJs().from(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]).distinct().select();

如果你有任何可能

D3.js

你可以做

d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]

https://github.com/mbostock/d3/wiki/Arrays#set_values

嵌套循环方法,用于删除数组中的重复项并保留元素的原始顺序。

var array = [1, 3, 2, 1, [5], 2, [4]]; // INPUT
var element = 0;var decrement = array.length - 1;while(element < array.length) {while(element < decrement) {if (array[element] === array[decrement]) {array.splice(decrement, 1);decrement--;} else {decrement--;}}decrement = array.length - 1;element++;}
console.log(array);// [1, 3, 2, [5], [4]]

说明:内循环将数组的第一个元素与从索引最高的元素开始的所有其他元素进行比较。向第一个元素递减,从数组中拼接一个副本。

当内循环完成时,外循环递增到下一个元素进行比较并重置数组的新长度。

复杂度为O(n)的Vanilla JS解决方案(此问题可能最快)。如果需要,修改hashFunction以区分对象(例如1和“1”)。第一个解决方案避免隐藏循环(在Array提供的函数中很常见)。

var dedupe = function(a){var hash={},ret=[];var hashFunction = function(v) { return ""+v; };var collect = function(h){if(hash.hasOwnProperty(hashFunction(h)) == false) // O(1){hash[hashFunction(h)]=1;ret.push(h); // should be O(1) for Arraysreturn;}};
for(var i=0; i<a.length; i++) // this is a loop: O(n)collect(a[i]);//OR: a.forEach(collect); // this is a loop: O(n)
return ret;}
var dedupe = function(a){var hash={};var isdupe = function(h){if(hash.hasOwnProperty(h) == false) // O(1){hash[h]=1;return true;}
return false;};
return a.filter(isdupe); // this is a loop: O(n)}

function remove_duplicates(array_){var ret_array = new Array();for (var a = array_.length - 1; a >= 0; a--) {for (var b = array_.length - 1; b >= 0; b--) {if(array_[a] == array_[b] && a != b){delete array_[b];}};if(array_[a] != undefined)ret_array.push(array_[a]);};return ret_array;}
console.log(remove_duplicates(Array(1,1,1,2,2,2,3,3,3)));

遍历、删除重复项并创建克隆数组占位符,因为数组索引不会更新。

向后循环以获得更好的性能(您的循环不需要不断检查数组的长度)

使用原生javascript函数从数组中删除重复项的最简洁方法是使用如下序列:

vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, [])

就像我在其他示例中看到的那样,在duce函数中不需要sliceindexOf!不过,将其与过滤器函数一起使用是有意义的:

vals.filter(function(v, i, a){ return i == a.indexOf(v) })

另一种ES6(2015)已经在一些浏览器上运行的方法是:

Array.from(new Set(vals))

甚至使用点差算子

[...new Set(vals)]

干杯!

function arrayDuplicateRemove(arr){var c = 0;var tempArray = [];console.log(arr);arr.sort();console.log(arr);for (var i = arr.length - 1; i >= 0; i--) {if(arr[i] != tempArray[c-1]){tempArray.push(arr[i])c++;}};console.log(tempArray);tempArray.sort();console.log(tempArray);}

除了是一个比当前答案(减去面向未来的ES6答案)更简单,更简洁的解决方案之外,我还测试了这个,它也快得多:

var uniqueArray = dupeArray.filter(function(item, i, self){return self.lastIndexOf(item) == i;});

一个警告:Array.lastIndexOf()是在IE9中添加的,所以如果你需要比这更低,你需要看看其他地方。

var duplicates = function(arr){var sorted = arr.sort();var dup = [];for(var i=0; i<sorted.length; i++){var rest  = sorted.slice(i+1); //slice the rest of arrayif(rest.indexOf(sorted[i]) > -1){//do indexOfif(dup.indexOf(sorted[i]) == -1)dup.push(sorted[i]);//store it in another arr}}console.log(dup);}
duplicates(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]);

我在其他一些问题上做了一个详细的比较,但注意到这是我想在这里分享的真正的地方。

我相信这是最好的办法

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{}));console.log(reduced);

好的…即使这个是O(n),其他的是O(n^2),我很好奇看到这个减少/搜寻列表和过滤器/indexOf组合之间的基准比较(我选择Jeetendras非常好的实现https://stackoverflow.com/a/37441144/4543207)。我准备了一个100K项数组,填充了0-9999范围内的随机正整数,它删除了重复项。我重复测试10次,结果的平均值表明它们在性能上不匹配。

  • 在Firefox v47中减少和lut:14.85ms与过滤器和索引:2836ms
  • 在chrome v51中减少和lut:23.90ms与过滤器和索引:1066ms

好吧,到目前为止还不错。但是这次让我们以ES6风格正确地做它。它看起来太酷了…!但是到目前为止,它将如何与强大的lut解决方案相抗衡对我来说是一个谜。让我们先看看代码,然后对其进行基准测试。

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],reduced = [...myArray.reduce((p,c) => p.set(c,true),new Map()).keys()];console.log(reduced);

哇,很短…!但是性能如何…?很漂亮…由于过滤器/indexOf的重量在我们的肩膀上提升,现在我可以测试一个数组1M范围0…99999的正整数的随机项,以从10个连续测试中获得平均值。我可以说这次是真正的匹配。自己看看结果:)

var ranar = [],red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],avg1 = [],avg2 = [],ts = 0,te = 0,res1 = [],res2 = [],count= 10;for (var i = 0; i<count; i++){ranar = (new Array(1000000).fill(true)).map(e => Math.floor(Math.random()*100000));ts = performance.now();res1 = red1(ranar);te = performance.now();avg1.push(te-ts);ts = performance.now();res2 = red2(ranar);te = performance.now();avg2.push(te-ts);}
avg1 = avg1.reduce((p,c) => p+c)/count;avg2 = avg2.reduce((p,c) => p+c)/count;
console.log("reduce & lut took: " + avg1 + "msec");console.log("map & spread took: " + avg2 + "msec");

你会用哪个…?没那么快…!不要被欺骗。Map处于位移状态。现在看…在上述所有情况下,我们用范围

var ranar = [],red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],avg1 = [],avg2 = [],ts = 0,te = 0,res1 = [],res2 = [],count= 100;for (var i = 0; i<count; i++){ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*100000000));ts = performance.now();res1 = red1(ranar);te = performance.now();avg1.push(te-ts);ts = performance.now();res2 = red2(ranar);te = performance.now();avg2.push(te-ts);}
avg1 = avg1.reduce((p,c) => p+c)/count;avg2 = avg2.reduce((p,c) => p+c)/count;
console.log("reduce & lut took: " + avg1 + "msec");console.log("map & spread took: " + avg2 + "msec");

现在这是Map()的壮观回归…!也许现在你可以做出更好的决定,当你想要删除欺骗。

好吧,我们现在都很高兴了。但是主角总是在掌声中排在最后。我相信你们中的一些人想知道Set对象会做什么。既然我们对ES6开放,而且我们知道Map是前几场比赛的赢家,让我们将Map和Set作为决赛进行比较。这次是典型的皇家马德里对巴塞罗那的比赛…或者是吗?让我们看看谁将赢得经典:)

var ranar = [],red1 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],red2 = a => Array.from(new Set(a)),avg1 = [],avg2 = [],ts = 0,te = 0,res1 = [],res2 = [],count= 100;for (var i = 0; i<count; i++){ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*10000000));ts = performance.now();res1 = red1(ranar);te = performance.now();avg1.push(te-ts);ts = performance.now();res2 = red2(ranar);te = performance.now();avg2.push(te-ts);}
avg1 = avg1.reduce((p,c) => p+c)/count;avg2 = avg2.reduce((p,c) => p+c)/count;
console.log("map & spread took: " + avg1 + "msec");console.log("set & A.from took: " + avg2 + "msec");

哇…男人…!出乎意料的是,它根本不是一个经典。更像巴塞罗那足球俱乐部对CA奥萨苏纳:))

这只是另一种解决方案,但与其他解决方案不同。

function diffArray(arr1, arr2) {var newArr = arr1.concat(arr2);newArr.sort();var finalArr = [];for(var i = 0;i<newArr.length;i++) {if(!(newArr[i] === newArr[i+1] || newArr[i] === newArr[i-1])) {finalArr.push(newArr[i]);}}return finalArr;}

泛型函数方法

以下是ES2015的通用和严格功能方法:

// small, reusable auxiliary functions
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const uncurry = f => (a, b) => f(a) (b);
const push = x => xs => (xs.push(x), xs);
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);
const some = f => xs => xs.some(apply(f));

// the actual de-duplicate function
const uniqueBy = f => foldl(acc => x => some(f(x)) (acc)? acc: push(x) (acc)) ([]);

// comparators
const eq = y => x => x === y;
// string equality case insensitive :Dconst seqCI = y => x => x.toLowerCase() === y.toLowerCase();

// mock data
const xs = [1,2,3,1,2,3,4];
const ys = ["a", "b", "c", "A", "B", "C", "D"];

console.log( uniqueBy(eq) (xs) );
console.log( uniqueBy(seqCI) (ys) );

我们可以很容易地从unqiueBy派生unique,或者使用更快的实现来使用Sets:

const unqiue = uniqueBy(eq);
// const unique = xs => Array.from(new Set(xs));

这种方法的好处:

  • 使用单独的比较函数的泛型解决方案
  • 声明式和简洁的实现
  • 重用其他小型通用函数

性能考虑

uniqueBy不像带有循环的命令式实现那么快,但由于它的泛型,它更具表现力。

如果你确定uniqueBy是应用程序中具体性能损失的原因,请将其替换为优化代码。也就是说,首先以功能、声明性的方式编写代码。之后,如果你遇到性能问题,请尝试优化导致问题的位置的代码。

内存消耗和垃圾收集

uniqueBy利用隐藏在其主体中的突变(push(x) (acc))。它重用累加器,而不是在每次迭代后将其丢弃。这减少了内存消耗和GC压力。由于这一副作用被包裹在函数内部,因此外部的一切都保持纯净。

这对于理解和在任何地方(甚至在Photoshop Script中)代码都非常简单。检查它!

var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl");
peoplenames = unique(peoplenames);alert(peoplenames);
function unique(array){var len = array.length;for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++)if(array[j] == array[i]){array.splice(j,1);j--;len--;}return array;}
//*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"]
function removeDuplicates (array) {var sorted = array.slice().sort()var result = []
sorted.forEach((item, index) => {if (sorted[index + 1] !== item) {result.push(item)}})return result}

到目前为止我遇到的最简单的。在es6中。

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl", "Mike", "Nancy"]
var noDupe = Array.from(new Set(names))

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

var lines = ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Nancy", "Carl"];var uniqueNames = [];
for(var i = 0; i < lines.length; i++){if(uniqueNames.indexOf(lines[i]) == -1)uniqueNames.push(lines[i]);}if(uniqueNames.indexOf(uniqueNames[uniqueNames.length-1])!= -1)uniqueNames.pop();for(var i = 0; i < uniqueNames.length; i++){document.write(uniqueNames[i]);document.write("<br/>");}

快速简便地使用豆沙-var array = ["12346","12347","12348","12349","12349"]; console.log(_.uniqWith(array,_.isEqual));

所以选择是:

let a = [11,22,11,22];let b = []

b = [ ...new Set(a) ];// b = [11, 22]
b = Array.from( new Set(a))// b = [11, 22]
b = a.filter((val,i)=>{return a.indexOf(val)==i})// b = [11, 22]
var uniqueCompnies = function(companyArray) {var arrayUniqueCompnies = [],found, x, y;
for (x = 0; x < companyArray.length; x++) {found = undefined;for (y = 0; y < arrayUniqueCompnies.length; y++) {if (companyArray[x] === arrayUniqueCompnies[y]) {found = true;break;}}
if ( ! found) {arrayUniqueCompnies.push(companyArray[x]);}}
return arrayUniqueCompnies;}
var arr = ["Adobe Systems Incorporated","IBX","IBX","BlackRock, Inc.","BlackRock, Inc.",];

aLink是一个简单的JavaScript数组对象。如果在索引显示删除重复记录的元素之前存在任何元素。我重复取消所有重复项。一个通道数组取消更多记录。

var srt_ = 0;var pos_ = 0;do {var srt_ = 0;for (var i in aLinks) {pos_ = aLinks.indexOf(aLinks[i].valueOf(), 0);if (pos_ < i) {delete aLinks[i];srt_++;}}} while (srt_ != 0);

一个简单但有效的技术是将filter方法与过滤器function(value, index){ return this.indexOf(value) == index }结合使用。

代码示例:

var data = [2,3,4,5,5,4];var filter = function(value, index){ return this.indexOf(value) == index };var filteredData = data.filter(filter, data );
document.body.innerHTML = '<pre>' + JSON.stringify(filteredData, null, '\t') +  '</pre>';

另见这个小提琴

解决方案1

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

解决方案2(使用Set)

Array.prototype.unique = function() {return Array.from(new Set(this));}

测试

var x=[1,2,3,3,2,1];x.unique() //[1,2,3]

性能

当我在chrome中测试两种实现(使用和不使用Set)的性能时,我发现使用Set的实现要快得多!

Array.prototype.unique1 = function() {var a = [];for (i = 0; i < this.length; i++) {var current = this[i];if (a.indexOf(current) < 0) a.push(current);}return a;}

Array.prototype.unique2 = function() {return Array.from(new Set(this));}
var x=[];for(var i=0;i<10000;i++){x.push("x"+i);x.push("x"+(i+1));}
console.time("unique1");console.log(x.unique1());console.timeEnd("unique1");


console.time("unique2");console.log(x.unique2());console.timeEnd("unique2");

此解决方案在函数内使用一个新数组和一个对象映射。它所做的只是循环遍历原始数组,并将每个整数添加到对象映射中。

`if (!unique[int])`

捕获此消息,因为对象上已经有一个具有相同编号的键属性。因此,跳过该编号并不允许将其推送到新数组中。

    function removeRepeats(ints) {var unique = {}var newInts = []
for (var i = 0; i < ints.length; i++) {var int = ints[i]
if (!unique[int]) {unique[int] = 1newInts.push(int)}}return newInts}
var example = [100, 100, 100, 100, 500]console.log(removeRepeats(example)) // prints [100, 500]

您可以简单地在JavaScript中执行此操作,并借助filter方法的第二个-index-参数:

var a = [2,3,4,5,5,4];a.filter(function(value, index){ return a.indexOf(value) == index });

或在短时间内

a.filter((v,i) => a.indexOf(v) == i)
const numbers = [1, 1, 2, 3, 4, 4];
function unique(array) {return array.reduce((a,b) => {let isIn = a.find(element => {return element === b;});if(!isIn){a.push(b);}return a;},[]);}
let ret = unique(numbers); // [1, 2, 3, 4]

使用Reduce和Fint的方法。

虽然ES6解决方案是最好的,但我很困惑为什么没有人展示以下解决方案:

function removeDuplicates(arr){o={}arr.forEach(function(e){o[e]=true})return Object.keys(o)}

这里要记住的是对象必须有唯一的键。我们正在利用这一点来删除所有重复项。我认为这将是最快的解决方案(在ES6之前)。

请记住,这也对数组进行了排序。

一行:

let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];let dup = [...new Set(names)];console.log(dup);

这里是简单的方法,没有任何特殊的库是特殊的函数,

name_list = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];get_uniq = name_list.filter(function(val,ind) { return name_list.indexOf(val) == ind; })
console.log("Original name list:"+name_list.length, name_list)console.log("\n Unique name list:"+get_uniq.length, get_uniq)

在此处输入图片描述

像这样使用Array.filter()

var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana'];
console.log('Actual Array: ' + actualArr);
var filteredArr = actualArr.filter(function(item, index) {if (actualArr.indexOf(item) == index)return item;});
console.log('Filtered Array: ' + filteredArr);

这可以在ES6中缩短到

actualArr.filter((item,index,self) => self.indexOf(item)==index);

这里是对Array.filter()的很好解释

ES2015,1-line,它与map链接良好,但仅适用于整数:

[1, 4, 1].sort().filter((current, next) => current !== next)

[1、4]

对于任何希望将具有重复元素的数组展平为一个唯一数组的人:

function flattenUniq(arrays) {var args = Array.prototype.slice.call(arguments);
var array = [].concat.apply([], args)
var result = array.reduce(function(prev, curr){if (prev.indexOf(curr) < 0) prev.push(curr);return prev;},[]);
return result;}
for (i=0; i<originalArray.length; i++) {if (!newArray.includes(originalArray[i])) {newArray.push(originalArray[i]);}}