如何使用 JavaScript 在数组中查找重复项?
使用 JavaScript 在数组中查找重复项,这在 Web 开发中,是比较常见的需求;前段时间,有梳理浅谈关于「函数式编程」的理解 一文,对函数式编程喜之不已
,因而在实际工作中,更喜欢尝试基于「函数式编程理念」,去解决问题。此文旨在探讨,在这种思想加持下,如何处理常见诉求。
函数式编程( Functional Programming)关注的是:描述要做什么,而不是如何做(describe what to do, rather than how to do it)。它强调避免使用程序状态以及易变对象,从而增加代码可读性、可维护性。因此,在实际代码中,应尽可能避免临时变量、循环、状态变化等。因而,基于 For 循环这种方案,便不在考虑之内。那怎样的做法,算是「最佳实践」呢?
使用 indexOf() 方法
在此方法中,所做的是:将数组中所有项的索引,与该元素第一次出现的索引进行比较。如果它们不匹配,则意味着该元素是重复的。所有这些元素都使用 filter()
方法在单独的数组中返回。示例代码如下:
const findDuplElemFromArray = arr => arr.filter((item, index) => arr.indexOf(item) !== index)
console.log(findDuplElemFromArray([1, 1, 2, 2, 3, 4, 5, 6]))
// Output: [ 1, 2 ]
上述代码虽然可以工作,但存在一个弊端:如果元素在数组中出现两次以上,则输出数组可能具有重复元素。
console.log(findDuplElemFromArray([1, 1, 1, 2, 2, 3, 4, 5, 6]))
// Output: [ 1, 1, 2 ]
为了避免这种情况,并能计算重复元素的数量,可以使用 use()
方法。
使用 has()
方法
const getRemovedDuplElems = arr => {
return [...new Set(arr)]
}
const getDuplicateElems = arr => {
const uniqueElemArr = new Set(arr);
return arr.filter(item => {
if (uniqueElemArr.has(item)) {
uniqueElemArr.delete(item);
} else {
return item;
}
});
}
const findDuplElemFromArray = (arr) => {
const duplicateElemArr = getDuplicateElems(arr)
return getRemovedDuplElems(duplicateElemArr)
}
console.log(findDuplElemFromArray([1, 1, 1, 2, 2, 3, 4, 5, 6]))
// Output: [ 1, 2 ]
上述解决方案,使用 has()
方法查找并返回重复元素。这比以前的方法更有效,因为 Set 中的每个值都必须是唯一的。当然,还可以使用其他方案,如对象和键值对、迭代遍历,但相比起来会更为复杂,就不多做探讨。
处理更为复杂的逻辑
更近一步,假如说需求变得更为复杂;所面临的数组类似下面这样,欲找出其中关键字 name
所重复的项,该如何优雅处理呢?
const tempTestArr = [
{ name: '刘亦菲', filmography: '金粉世家' },
{ name: '古天乐', filmography: '神雕侠侣' },
{ name: '刘亦菲', filmography: '神雕侠侣' },
{ name: '李若彤', filmography: '神雕侠侣' },
{ name: '古天乐', filmography: '寻秦记' },
{ name: '刘亦菲', filmography: '梦华录' },
{ name: '舒畅', filmography: '天龙八部' },
];
对于这个诉求,当然可以使用多重遍历,但那并不是想使用的方案,因而有采用如下思路方案:
- 将
name
项列出来,组装出一个新数组 A; - 找出其中重复的项,并得到另一个数组 B;
- 过滤原数组,返回 B 数组中所包含的 name 项,即想要结果;
const getRemovedDuplElems = (arr) => {
return [...new Set(arr)];
};
const getDuplicateElems = arr => {
const uniqueElemArr = new Set(arr);
return arr.filter(item => {
if (uniqueElemArr.has(item)) {
uniqueElemArr.delete(item);
} else {
return item;
}
});
}
const findDuplElemFromArray = (arr) => {
const duplicateElemArr = getDuplicateElems(arr)
return getRemovedDuplElems(duplicateElemArr)
}
const getNewArrByKey = (arr, key = '') => {
return arr.map(item => item[key]);
}
const getDuplicatesFromArray = arr => {
const specifiedKeyArr = getNewArrByKey(arr, 'name')
const duplicateElemArr = findDuplElemFromArray(specifiedKeyArr);
return arr.filter(item => !!duplicateElemArr.includes(item.name));
};
const tempTestArr = [
{ name: '刘亦菲', filmography: '金粉世家' },
{ name: '古天乐', filmography: '神雕侠侣' },
{ name: '刘亦菲', filmography: '神雕侠侣' },
{ name: '李若彤', filmography: '神雕侠侣' },
{ name: '古天乐', filmography: '寻秦记' },
{ name: '刘亦菲', filmography: '梦华录' },
{ name: '舒畅', filmography: '天龙八部' },
];
console.log(getDuplicatesFromArray(tempTestArr))
// Output:
// [
// { name: '刘亦菲', filmography: '金粉世家' },
// { name: '古天乐', filmography: '神雕侠侣' },
// { name: '刘亦菲', filmography: '神雕侠侣' },
// { name: '古天乐', filmography: '寻秦记' },
// { name: '刘亦菲', filmography: '梦华录' }
// ]
基于这种思路,所走的时间复杂度,并不是很多,与空间复杂度做了平衡。虽然谈不上最佳实践,但代码可以很清晰,而且函数可复用,易于修改、维护。从整个实现来看,临时变量或多或少,还是需要用到(去掉也是可以,但会增加阅读难度);可见灵活使用很重要,不当拘泥于一种思想。朋友,如果您有更适宜的方案,欢请留言分享。
原文首发于:如何使用 JavaScript 在数组中查找重复项?|悠然宜想亭。