我需要检查一个JavaScript数组,看看是否有任何重复的值。最简单的方法是什么?我只需要找到复制的值是什么——实际上我不需要它们的索引,也不需要它们复制了多少次。
我知道我可以循环遍历数组并检查所有其他值是否匹配,但似乎应该有更简单的方法。
类似的问题:
获取JavaScript数组中所有唯一的值(删除重复值)
我需要检查一个JavaScript数组,看看是否有任何重复的值。最简单的方法是什么?我只需要找到复制的值是什么——实际上我不需要它们的索引,也不需要它们复制了多少次。
我知道我可以循环遍历数组并检查所有其他值是否匹配,但似乎应该有更简单的方法。
类似的问题:
获取JavaScript数组中所有唯一的值(删除重复值)
当前回答
修改@RaphaelMontanaro的解决方案,借鉴@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;
}
感谢你优雅的解决方案,@Nosredna!
其他回答
function remove_dups(arrayName){
var newArray = new Array();
label:for(var i=0; i<arrayName.length; i++ ){
for(var j=0; j<newArray.length;j++ ){
if(newArray[j]==arrayName[i]){
continue label;
}
}
newArray[newArray.length] = arrayName[i];
}
return newArray;
}
从Raphael Montanaro的回答,它可以改进使用数组/对象项如下。
function eliminateDuplicates(arr) {
var len = arr.length,
out = [],
obj = {};
for (var key, i=0; i < len; i++) {
key = JSON.stringify(arr[i]);
obj[key] = (obj[key]) ? obj[key] + 1 : 1;
}
for (var key in obj) {
out.push(JSON.parse(key));
}
return [out, obj];
}
注意:对于不支持JSON的浏览器,需要使用JSON库。
更新:以下使用一个优化的组合策略。它优化了原语查找,以受益于散列O(1)查找时间(在原语数组上惟一地运行是O(n))。对象查找通过在遍历对象时用唯一id标记对象来优化,因此识别重复对象也是每个项目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集合可用,那么有一个更简单、更快的版本。(shim适用于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;
}
});
}
公认的答案是最完美的,但正如一些用户指出的那样,对于一个元素重复超过2次的情况,它将给出具有重复元素的数组:
这个解决方案也涵盖了这些场景:
const peoples = [
{id: 1, name:"Arjun"},
{id: 2, name:"quinze"},
{id: 3, name:"catorze"},
{id: 1, name:"Arjun"},
{id: 4, name:"dezesseis"},
{id: 1, name:"Arjun"},
{id: 2, name:"quinze"},
{id: 3, name:"catorzee"}
]
function repeated(ppl){
const newppl = ppl.slice().sort((a,b) => a.id -b.id);
let rept = [];
for(let i = 0; i < newppl.length-1 ; i++){
if (newppl[i+1].id == newppl[i].id){
rept.push(newppl[i+1]);
}
}
return [...new Set(rept.map(el => el.id))].map(rid =>
rept.find(el => el.id === rid)
);
}
repeated(peoples);
大多数答案我都不喜欢。
为什么?太复杂,代码太多,效率低下,许多代码没有回答问题,即找到重复项(而不是给出一个没有重复项的数组)。
Next函数返回所有副本:
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);
});
}
也许其他人也这么想。