如何使用 JavaScript 在数组中查找重复项?

前端开发 Jun 8, 2022

使用 JavaScript 在数组中查找重复项,这在 Web 开发中,是比较常见的需求;前段时间,有梳理浅谈关于「函数式编程」的理解 一文,对函数式编程喜之不已,因而在实际工作中,更喜欢尝试基于「函数式编程理念」,去解决问题。此文旨在探讨,在这种思想加持下,如何处理常见诉求。

JavaScript 函数式编程理念及应用

函数式编程( 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: '天龙八部' },
];

对于这个诉求,当然可以使用多重遍历,但那并不是想使用的方案,因而有采用如下思路方案:

  1. name 项列出来,组装出一个新数组 A;
  2. 找出其中重复的项,并得到另一个数组 B;
  3. 过滤原数组,返回 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 在数组中查找重复项?|悠然宜想亭

猜您可能感兴趣的文章

Tags

轩帅

来自陕南一隅;现栖身于深圳福田,作为一介程序员。略崇文喜武,大爱豪杰美人,也尚科技。

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.