获取数组中的所有非唯一值(即:重复/不止一次)
我需要检查一个JavaScript数组,看看是否有重复的值。 什么是最简单的方法来做到这一点? 我只需要find重复的值是什么 – 我实际上并不需要他们的索引或重复了多less次。
我知道我可以遍历数组,并检查所有其他值的匹配,但似乎应该有一个更简单的方法。 有任何想法吗? 谢谢!
类似的问题:
- 获取数组中的所有唯一值(删除重复项)
您可以对数组进行sorting,然后遍历它,然后查看下一个(或前一个)索引是否与当前相同。 假设你的sortingalgorithm是好的,它应该小于O(n 2 ):
var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7]; var sorted_arr = arr.slice().sort(); // You can define the comparing function here. // JS by default uses a crappy string compare. // (we use slice to clone the array so the // original array won't be modified) var results = []; for (var i = 0; i < sorted_arr.length - 1; i++) { if (sorted_arr[i + 1] == sorted_arr[i]) { results.push(sorted_arr[i]); } } console.log(results);
如果你想要重复这些重复的东西,试试这个好的解决scheme:
function eliminateDuplicates(arr) { var i, len=arr.length, out=[], obj={}; for (i=0;i<len;i++) { obj[arr[i]]=0; } for (i in obj) { out.push(i); } return out; }
它是我见过的最棒的JavaScript代码片段之一。 原文发表在这里: http : //dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
这是我从重复线程(!)的答案:
厌倦了看到for循环或jQuery的所有不好的例子。 JavaScript现在有这个完美的工具:sorting,映射和减less。
查找重复的项目
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.count return a }, {}) var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1) console.log(duplicates) // [ 'Nancy' ]
更多的function语法:
@Dmytro-Laptin指出一些代码被删除。 这是相同代码的更紧凑的版本。 使用一些ES6技巧和更高阶的function:
const names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'] const count = names => names.reduce((a, b) => Object.assign(a, {[b]: (a[b] || 0) + 1}), {}) const duplicates = dict => Object.keys(dict).filter((a) => dict[a] > 1) console.log(count(names)) // { Mike: 1, Matt: 1, Nancy: 2, Adam: 1, Jenny: 1, Carl: 1 } console.log(duplicates(count(names))) // [ 'Nancy' ]
使用Function.prototype.bind:
// prep const arr = Array.from('Learn more javascript dude'); const counter = (prev, next) => Object.assign(prev, { [next] : (prev[next] || 0) + 1 }); const singles = function(key){ return this[key] === 1 }; const multiples = function(key){ return this[key] > 1 }; // work const counted = arr.reduce(counter, {}); const filtered = Object.keys(counted).filter(multiples.bind(counted)); //[ "e", "a", "r", " ", "d" ] console.log(filtered);
你可以添加这个函数,或者调整它,并将其添加到Javascript的数组原型:
Array.prototype.unique = function () { var r = new Array(); o:for(var i = 0, n = this.length; i < n; i++) { for(var x = 0, y = r.length; x < y; x++) { if(r[x]==this[i]) { alert('this is a DUPE!'); continue o; } } r[r.length] = this[i]; } return r; } var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9]; var unique = arr.unique(); alert(unique);
更新:以下使用一个优化的组合策略。 它优化了原始查找,以从散列O(1)查找时间(在基元数组上运行unique
的O(n))获益。 对象查找通过标记具有唯一标识的对象进行优化,同时迭代通过如此识别重复对象也是O(1)每个项目和O(n)的整个列表。 唯一的例外是冻结的项目,但这些是罕见的,并使用数组和indexOf提供回退。
var unique = function(){ var hasOwn = {}.hasOwnProperty, toString = {}.toString, uids = {}; function uid(){ var key = Math.random().toString(36).slice(2); return key in uids ? uid() : uids[key] = key; } function unique(array){ var strings = {}, numbers = {}, others = {}, tagged = [], failed = [], count = 0, i = array.length, item, type; var id = uid(); while (i--) { item = array[i]; type = typeof item; if (item == null || type !== 'object' && type !== 'function') { // primitive switch (type) { case 'string': strings[item] = true; break; case 'number': numbers[item] = true; break; default: others[item] = item; break; } } else { // object if (!hasOwn.call(item, id)) { try { item[id] = true; tagged[count++] = item; } catch (e){ if (failed.indexOf(item) === -1) failed[failed.length] = item; } } } } // remove the tags while (count--) delete tagged[count][id]; tagged = tagged.concat(failed); count = tagged.length; // append primitives to results for (i in strings) if (hasOwn.call(strings, i)) tagged[count++] = i; for (i in numbers) if (hasOwn.call(numbers, i)) tagged[count++] = +i; for (i in others) if (hasOwn.call(others, i)) tagged[count++] = others[i]; return tagged; } return unique; }();
如果你有ES6集合,那么有一个更简单,更快的版本。 (适用于IE9 +和其他浏览器: https : //github.com/Benvie/ES6-Harmony-Collections-Shim )
function unique(array){ var seen = new Set; return array.filter(function(item){ if (!seen.has(item)) { seen.add(item); return true; } }); }
这应该得到你想要的,只是重复。
function find_duplicates(arr) { var len=arr.length, out=[], counts={}; for (var i=0;i<len;i++) { var item = arr[i]; counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1; if (counts[item] === 2) { out.push(item); } } return out; } find_duplicates(['one',2,3,4,4,4,5,6,7,7,7,'pig','one']); // -> ['one',4,7] in no particular order.
使用underscore.js
function hasDuplicate(arr){ return (arr.length != _.uniq(arr).length); }
在数组中查找重复的值
这应该是在数组中实际查找重复值的最短途径之一。 正如OP特别要求的那样, 这并不会删除重复项,而是find它们 。
var input = [1, 2, 3, 1, 3, 1]; var duplicates = input.reduce(function(acc, el, i, arr) { if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc; }, []); document.write(duplicates); // = 1,3 (actual array == [1, 3])
var a = [324,3,32,5,52,2100,1,20,2,3,3,2,2,2,1,1,1].sort(); a.filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});
或者添加到Array的prototyp.chain
//copy and paste: without error handling Array.prototype.unique = function(){return this.sort().filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});}
看到这里: https : //gist.github.com/1305056
var a = ["a","a","b","c","c"]; a.filter(function(value,index,self){ return (self.indexOf(value) !== index )})
当你所需要的是检查这个问题中没有重复的时候,你可以使用every()
方法:
[1, 2, 3].every(function(elem, i, array){return array.lastIndexOf(elem) === i}) // true [1, 2, 1].every(function(elem, i, array){return array.lastIndexOf(elem) === i}) // false
请注意, every()
不适用于IE 8及以下版本。
我使用lastIndexOf()
是因为它可能比indexOf()
效率更高,如果every()
所做的函数callback都是按索引顺序进行的,但这并没有得到证实。
在CoffeeScript中,我使用这个:
Array::duplicates = -> not @every((elem, i, array) -> array.lastIndexOf(elem) is i) [1, 2, 3].duplicates() // false [1, 2, 1].duplicates() // true
从3个数组(或更多)中查找唯一值:
Array.prototype.unique = function () { var arr = this.sort(), i; // input must be sorted for this to work for( i=arr.length; i--; ) arr[i] === arr[i-1] && arr.splice(i,1); // remove duplicate item return arr; } var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9], arr2 = [1,2,511,12,50], arr3 = [22], unique = arr.concat(arr2, arr3).unique(); console.log(unique); // [22, 50, 12, 511, 2, 1, 9, 5, 8, 7, 3, 6, 4]
对于旧的浏览器,只需要一个数组indexO的polyfill:
if (!Array.prototype.indexOf){ Array.prototype.indexOf = function(elt /*, from*/){ var len = this.length >>> 0; var from = Number(arguments[1]) || 0; from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; for (; from < len; from++){ if (from in this && this[from] === elt) return from; } return -1; }; }
使用“inArray”的jQuery解决scheme:
if( $.inArray(this[i], arr) == -1 )
而不是添加“Array.prototype.indexOf”
下面的函数(已经提到的removedDuplicates函数的一个变体)似乎是做了这个诀窍,返回test2,1,7,5作为input[“test”,“test2”,“test2”,1,1,1,2 ,3,4,5,6,7,7,10,22,43,1,5,8]的情况下,
请注意,JavaScript中的问题比大多数其他语言更为奇怪,因为JavaScript数组几乎可以容纳任何东西。 请注意,使用sorting的解决scheme可能需要提供适当的sortingfunction – 我还没有尝试过这种路线。
这个特定的实现适用于(至less)string和数字。
function findDuplicates(arr) { var i, len=arr.length, out=[], obj={}; for (i=0;i<len;i++) { if (obj[arr[i]] != null) { if (!obj[arr[i]]) { out.push(arr[i]); obj[arr[i]] = 1; } } else { obj[arr[i]] = 0; } } return out; }
这是一个非常轻松简单的方法:
var codes = dc_1.split(','); var i = codes.length; while (i--) { if (codes.indexOf(codes[i]) != i) { codes.splice(i,1); } }
ES5只(即,它需要一个filter()填充IE8和以下):
var arrayToFilter = [ 4, 5, 5, 5, 2, 1, 3, 1, 1, 2, 1, 3 ]; arrayToFilter. sort(). filter( function(me,i,arr){ return (i===0) || ( me !== arr[i-1] ); });
var input = ['a', 'b', 'a', 'c', 'c'], duplicates = [], i, j; for (i = 0, j = input.length; i < j; i++) { if (duplicates.indexOf(input[i]) === -1 && input.indexOf(input[i], i+1) !== -1) { duplicates.push(input[i]); } } console.log(duplicates);
修改@ RaphaelMontanaro的解决scheme,从@ Nosredna的博客借用,这里是你可以做什么,如果你只是想确定你的数组中的重复元素。
function identifyDuplicatesFromArray(arr) { var i; var len = arr.length; var obj = {}; var duplicates = []; for (i = 0; i < len; i++) { if (!obj[arr[i]]) { obj[arr[i]] = {}; } else { duplicates.push(arr[i]); } } return duplicates; }
感谢优雅的解决scheme,@Nosredna!
我不喜欢大多数答案。
为什么? 太复杂,代码太多,代码效率低下,许多人不回答这个问题,那就是find重复的内容(而不是没有重复的数组)。
下一个函数返回所有重复项:
function GetDuplicates(arr) { var i, out=[], obj={}; for (i=0; i < arr.length; i++) obj[arr[i]] == undefined ? obj[arr[i]] ++ : out.push(arr[i]); return out; }
因为大多数情况下,返回所有重复项是没有用的,只是告诉哪些重复值存在。 在这种情况下,你返回一个数组与独特的重复;-)
function GetDuplicates(arr) { var i, out=[], obj={}; for (i=0; i < arr.length; i++) obj[arr[i]] == undefined ? obj[arr[i]] ++ : out.push(arr[i]); return GetUnique(out); } function GetUnique(arr) { return $.grep(arr, function(elem, index) { return index == $.inArray(elem, arr); }); }
也许别人也这么想。
var arr = [2, 1, 2, 2, 4, 4, 2, 5]; function returnDuplicates(arr) { return arr.reduce(function(dupes, val, i) { if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) { dupes.push(val); } return dupes; }, []); } alert(returnDuplicates(arr));
为了解决上述的O(n)时间复杂度(不分类)。
var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7]; var obj={}; for(var i=0;i<arr.length;i++){ if(!obj[arr[i]]){ obj[arr[i]]=1; } else { obj[arr[i]]=obj[arr[i]]+1; } } var result=[] for(var key in obj){ if(obj[key]>1){ result.push(Number(key)) // change this to result.push(key) to find duplicate strings in an array } } console.log(result)
这可能是永久删除arrays中重复项的最快方法之一,它比这里的大多数函数快10倍以上。Safari中的速度提高了78倍
function toUnique(a,b,c){//array,placeholder,placeholder b=a.length; while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1) } var array=[1,2,3,4,5,6,7,8,9,0,1,2,1]; toUnique(array); console.log(array);
- testing: http : //jsperf.com/wgu
- 演示: http : //jsfiddle.net/46S7g/
- 更多: https : //stackoverflow.com/a/25082874/2450730
如果你不能读取上面的代码请阅读javascript书或这里是关于较短的代码的一些解释。 https://stackoverflow.com/a/21353032/2450730
编辑正如注释中所述,这个函数确实返回一个数组与唯一,然而问题要求find重复。 在这种情况下,对这个函数的一个简单的修改允许把重复项推入一个数组,然后使用前面的函数toUnique
去除重复项的重复项。
function theDuplicates(a,b,c,d){//array,placeholder,placeholder b=a.length,d=[]; while(c=--b)while(c--)a[b]!==a[c]||d.push(a.splice(c,1)) } var array=[1,2,3,4,5,6,7,8,9,0,1,2,1]; toUnique(theDuplicates(array));
function GetDuplicates(arr) { var i = 0, m = []; return arr.filter(function (n) { return !m[n] * ~arr.indexOf(n, m[n] = ++i); }); }
使用“包含”来testing元素是否已经存在。
var arr = [1, 1, 4, 5, 5], darr = [], duplicates = []; for(var i = 0; i < arr.length; i++){ if(darr.includes(arr[i]) && !duplicates.includes(arr[i])) duplicates.push(arr[i]) else darr.push(arr[i]); } console.log(duplicates);
<h3>Array with duplicates</h3> <p>[1, 1, 4, 5, 5]</p> <h3>Array with distinct elements</h3> <p>[1, 4, 5]</p> <h3>duplicate values are</h3> <p>[1, 5]</p>
ES6提供的Set数据结构基本上是一个不接受重复的数组。 使用Set数据结构,可以非常简单地在数组中find重复项(仅使用一个循环)。
这是我的代码
function findDuplicate(arr) { var set = new Set(); var duplicates = new Set(); for (let i = 0; i< arr.length; i++) { var size = set.size; set.add(arr[i]); if (set.size === size) { duplicates.add(arr[i]); } } return duplicates; }
我觉得最简单的解决scheme就是使用indexOf
仅向数组推送唯一元素的完整示例。
var arr = ['a','b','c','d','a','b','c','d']; var newA = []; for(var i = 0; i < arr.length; i++){ if(newA.indexOf(arr[i]) === -1){ newA.push(arr[i]); } }
使用ES6语法的简单代码(返回重复sorting的数组):
let duplicates = a => {d=[]; a.sort((a,b) => ab).reduce((a,b)=>{a==b&&!d.includes(a)&&d.push(a); return b}); return d};
如何使用:
duplicates([1,2,3,10,10,2,3,3,10]);
Prototype库有一个uniq函数,它返回的数组没有模糊。 这只是工作的一半。
只是在上面添加一些理论。
在比较模型中,查找重复数据具有O(n * log(n))的下限。理论上讲,你不可能比第一次sorting更好,然后顺序地移除列表中的所有重复项。
如果要查找线性(O(n)) 预期时间的重复项,可以散列列表中的每个元素; 如果发生碰撞,请删除/标记为重复,然后继续。
另一种方法是使用下划线。 Numbers是源数组,dupe有可能的重复值。
var itemcounts = _.countBy(numbers, function (n) { return n; }); var dupes = _.reduce(itemcounts, function (memo, item, idx) { if (item > 1) memo.push(idx); return memo; }, []);
我认为下面是最简单和最快的O(n)方法来完成你所问的:
function getDuplicates( arr ) { var i, value; var all = {}; var duplicates = []; for( i=0; i<arr.length; i++ ) { value = arr[i]; if( all[value] ) { duplicates.push( value ); all[value] = false; } else if( typeof all[value] == "undefined" ) { all[value] = true; } } return duplicates; }
或者对于ES5或更高版本:
function getDuplicates( arr ) { var all = {}; return arr.reduce(function( duplicates, value ) { if( all[value] ) { duplicates.push(value); all[value] = false; } else if( typeof all[value] == "undefined" ) { all[value] = true; } return duplicates; }, []); }