如何检查对象数组是否具有重复的属性值?


76

我需要一些遍历数组的帮助,我一直陷于困境或重新发明轮子。

values = [
    { name: 'someName1' },
    { name: 'someName2' },
    { name: 'someName1' },
    { name: 'someName1' }
]

如何检查数组中是否有两个(或多个)相同的名称值?我不需要计数器,只需在数组值不是唯一的情况下设置一些变量即可。请记住,数组长度是动态的,数组值也是动态的。


@AmiTavory至少有一个明显的区别-这个问题着眼于一组基本arr = [9, 9, 9, 111, 2, 3, 3, 3, 4, 4, 5, 7];元素(),而这着眼于基于对象属性的重复数据删除。也许是语义上的,但是那里获得投票最高的两个答案并不能完全解决这种情况。/giphy the more you know(我意识到这不会做任何事情)
鲁芬(Ruffin

@ruffin点。已删除评论。
阿米·塔沃里

Answers:


85

使用array.prototype.maparray.prototype.some

var values = [
    { name: 'someName1' },
    { name: 'someName2' },
    { name: 'someName4' },
    { name: 'someName2' }
];

var valueArr = values.map(function(item){ return item.name });
var isDuplicate = valueArr.some(function(item, idx){ 
    return valueArr.indexOf(item) != idx 
});
console.log(isDuplicate);

JSFIDDLE。


3
indexOf如果数组很大,将导致非常糟糕的性能。
thefourtheye 2015年

9
我将返回部分替换为:return valueArr.indexOf(item,idx + 1)!== -1
Orelsanpls

60

ECMA Script 6版本

如果您在支持ECMA Script 6的环境中Set,则可以使用Array.prototype.some和这样的Set对象

let seen = new Set();
var hasDuplicates = values.some(function(currentObject) {
    return seen.size === seen.add(currentObject.name).size;
});

在这里,我们将每个对象name插入,Set然后检查size添加前后是否相同。之所以Set.size可行,是因为返回一个基于唯一数据的数字(如果数据是唯一的,则set仅添加条目)。如果/当您有重复的名称时,大小不会增加(因为数据不会唯一),这意味着我们将已经看到了当前名称,并且它将返回true。


ECMA Script 5版本

如果没有Set支持,则可以使用普通的JavaScript对象本身,如下所示

var seen = {};
var hasDuplicates = values.some(function(currentObject) {

    if (seen.hasOwnProperty(currentObject.name)) {
        // Current name is already seen
        return true;
    }

    // Current name is being seen for the first time
    return (seen[currentObject.name] = false);
});

这样可以简洁地写出来

var seen = {};
var hasDuplicates = values.some(function (currentObject) {
    return seen.hasOwnProperty(currentObject.name)
        || (seen[currentObject.name] = false);
});

注意:在两种情况下,我们都使用Array.prototype.some它,因为它会短路。一旦从函数获得真实值,它将true立即返回,不会处理其余元素。


有趣的方法,使用hasOwnProperty。在您评论的其他一些答案中,我发现indexOf在大型阵列中性能会很差。您建议的上述ES5方法对大型对象总体而言性能更友好吗?
乔什·

@JoshBeamindexOf将必须迭代数组以找出元素是否存在,但是使用散列的任何方法都将更快。因此,如果阵列很大,则ES5和ES6方式都将更快。
thefourtheye 2015年

我如何确定它将处理其余元素?
Anna Smother '16

@AnnaSmother如果要处理所有元素,请forEach自己使用和编写逻辑。
thefourtheye '16

1
@chovy问题是:“如何检查数组中是否有两个(或多个)相同的名称值?我不需要计数器,只要数组值不是唯一的,只需设置一些变量即可。” 这与删除重复项无关。我认为这是最好的答案!
calcazar

10

在TS和ES6中,您可以创建一个具有唯一属性的新Set,并将其大小与原始数组进行比较。

const values = [
  { name: 'someName1' },
  { name: 'someName2' },
  { name: 'someName3' },
  { name: 'someName1' }
]

const uniqueValues = new Set(values.map(v => v.name));

if (uniqueValues.size < values.length) {
  console.log('duplicates found')
}


3

要知道简单数组是否有重复项,我们可以比较相同值的第一个最后一个索引:

功能:

var hasDupsSimple = function(array) {

    return array.some(function(value) {                            // .some will break as soon as duplicate found (no need to itterate over all array)
       return array.indexOf(value) !== array.lastIndexOf(value);   // comparing first and last indexes of the same value
    })
}

测试:

hasDupsSimple([1,2,3,4,2,7])
// => true

hasDupsSimple([1,2,3,4,8,7])
// => false

hasDupsSimple([1,"hello",3,"bye","hello",7])
// => true

对于对象数组,我们需要先将对象值转换为简单数组:

使用以下命令将对象数组转换为简单数组map

var hasDupsObjects = function(array) {

  return array.map(function(value) {
    return value.suit + value.rank

  }).some(function(value, index, array) { 
       return array.indexOf(value) !== array.lastIndexOf(value);  
     })
}

测试:

var cardHand = [
  { "suit":"spades", "rank":"ten" },
  { "suit":"diamonds", "rank":"ace" },
  { "suit":"hearts", "rank":"ten" },
  { "suit":"clubs", "rank":"two" },
  { "suit":"spades", "rank":"three" },
]

hasDupsObjects(cardHand);
// => false

var cardHand2 = [
  { "suit":"spades", "rank":"ten" },
  { "suit":"diamonds", "rank":"ace" },
  { "suit":"hearts", "rank":"ten" },
  { "suit":"clubs", "rank":"two" },
  { "suit":"spades", "rank":"ten" },
]

hasDupsObjects(cardHand2);
// => true

如何找到索引以及最新的重复值
暗喻Vishwanath

3

如果您正在寻找布尔值,最快的方法是

var values = [
    { name: 'someName1' },
    { name: 'someName2' },
    { name: 'someName1' },
    { name: 'someName1' }
]

// solution
var hasDuplicate = false;
values.map(v => v.name).sort().sort((a, b) => {
  if (a === b) hasDuplicate = true
})
console.log('hasDuplicate', hasDuplicate)


2

使用Underscore.js可以使用Underscore完成几种方法。这是其中之一。检查数组是否已经是唯一的。

function isNameUnique(values){
    return _.uniq(values, function(v){ return v.name }).length == values.length
}

使用香草JavaScript 通过检查数组中是否没有重复的名称。

function isNameUnique(values){
    var names = values.map(function(v){ return v.name });
    return !names.some(function(v){ 
        return names.filter(function(w){ return w==v }).length>1 
    });
}


1

您可以使用map仅返回名称,然后使用此forEach技巧来检查它是否存在至少两次:

var areAnyDuplicates = false;

values.map(function(obj) {
    return obj.name;
}).forEach(function (element, index, arr) {
    if (arr.indexOf(element) !== index) {
        areAnyDuplicates = true;
    }
});

小提琴


indexOf如果数组很大,将导致非常糟糕的性能。
thefourtheye 2015年

1
//checking duplicate elements in an array
var arr=[1,3,4,6,8,9,1,3,4,7];
var hp=new Map();
console.log(arr.sort());
var freq=0;
for(var i=1;i<arr.length;i++){
// console.log(arr[i-1]+" "+arr[i]);
if(arr[i]==arr[i-1]){
freq++;

}
else{
hp.set(arr[i-1],freq+1);
freq=0;
}
}
console.log(hp);

使用节点scriptname.js复制和粘贴运行
ravi '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.