如何检查对象数组是不是具有重复的属性值?
Posted
技术标签:
【中文标题】如何检查对象数组是不是具有重复的属性值?【英文标题】:How can I check if the array of objects have duplicate property values?如何检查对象数组是否具有重复的属性值? 【发布时间】:2015-08-24 11:21:19 【问题描述】:我在遍历数组时需要一些帮助,但我总是被卡住或重新发明***。
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
(我意识到这不会做任何事情)
【参考方案1】:
ECMA 脚本 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 脚本 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 方式通常对较大的对象更友好吗?
@JoshBeam indexOf
将不得不迭代数组以找出元素是否存在,但任何使用散列的东西都会快得多。因此,如果数组很大,ES5 和 ES6 方式都会快得多。
我如何确保它将处理其余的元素?
@AnnaSmother 如果要处理所有元素,那么使用forEach
并自己编写逻辑。
@chovy 问题是:“我如何检查数组中是否有两个(或更多)同名值?我不需要计数器,如果数组值不唯一,只需设置一些变量。”这与删除重复项无关。我认为这是最好的答案!【参考方案2】:
您可以使用map
仅返回名称,然后使用此forEach
技巧检查它是否至少存在两次:
var areAnyDuplicates = false;
values.map(function(obj)
return obj.name;
).forEach(function (element, index, arr)
if (arr.indexOf(element) !== index)
areAnyDuplicates = true;
);
Fiddle
【讨论】:
indexOf
如果数组很大,性能会很差。【参考方案3】:
使用array.prototype.map 和array.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);
【讨论】:
indexOf
如果数组很大,性能会很差。
我将返回部分替换为:return valueArr.indexOf(item, idx + 1) !== -1
另一个选项可以是new Set(arr).size !== arr.length
来检查数组是否有重复。
@JoelFernando - 答案写于 6 年前及以下,有人添加了与 Set
一起使用的 ES6 答案。您的答案将适用于一系列原语。这里的问题是关于一组对象,其中内部属性是我们不想复制的对象。【参考方案4】:
使用 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
);
【讨论】:
【参考方案5】:尝试一个简单的循环:
var repeat = [], tmp, i = 0;
while(i < values.length)
repeat.indexOf(tmp = values[i++].name) > -1 ? values.pop(i--) : repeat.push(tmp)
Demo
【讨论】:
这只是以它们的重复数据删除数组结束。【参考方案6】:要知道简单数组是否有重复,我们可以比较相同值的 first 和 last 索引:
功能:
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
【讨论】:
如何找到索引以及最新的重复值 @SystemsRebooter,谢谢!!正是我想要的。【参考方案7】:如果您正在寻找布尔值,最快的方法是
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)
【讨论】:
【参考方案8】://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 复制粘贴运行【参考方案9】:在 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')
【讨论】:
这其实是最好的答案【参考方案10】:添加更新的 es6 函数以检查数组中的唯一值和重复值。这个函数是模块化的,可以在整个代码库中重用。感谢以上所有帖子。
/* checks for unique keynames in array */
const checkForUnique = (arrToCheck, keyName) =>
/* make set to remove duplicates and compare to */
const uniqueValues = [...new Set(arrToCheck.map(v => v[keyName]))];
if(arrToCheck.length !== uniqueValues.length)
console.log('NOT UNIQUE')
return false
return true
let arr = [name:'joshua',name:'tony',name:'joshua']
/* call function with arr and key to check for */
let isUnique = checkForUnique(arr,'name')
【讨论】:
【参考方案11】:试试这个功能,它通过一步删除重复项来扩展您的原始问题。您会得到一个删除了重复项的返回数组。
const test = [
name: 'someName1' ,
name: 'someName1' ,
name: 'someName2' ,
name: 'someName3'
]
function removeDup(arrayOfObjects)
if (new Set(arrayOfObjects.map((v) => v.name)).size < arrayOfObjects.length)
const _set = new Set();
const _data = arrayOfObjects;
for (const i in _data)
_set.add(JSON.stringify(_data[i]));
return Array.from(_set).map((i) =>
JSON.parse(i)
);
const res = removeDup(test)
console.log(res)
【讨论】:
以上是关于如何检查对象数组是不是具有重复的属性值?的主要内容,如果未能解决你的问题,请参考以下文章
Angular 2 / Typescript - 如何检查对象数组以查看属性是不是具有相同的值?
JavaScript:检查对象数组中是不是存在重复的键值并删除所有但最近添加的具有该键值的对象