如何使用 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

nicejade

轩帅,字琼璞,逍遥自在轩城主,晚晴幽草轩轩主,静轩之别苑阁主,悠然宜想亭主持。

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.