悠悠楠杉
如何用JavaScript高效合并数组并去重:实战技巧详解
如何用JavaScript高效合并数组并去重:实战技巧详解
一、理解数组去重的核心需求
在实际开发中,我们经常需要处理从不同数据源获取的数组数据。比如:
javascript
const titles = ['前端开发', 'JavaScript技巧', 'ES6新特性'];
const keywords = ['数组去重', 'JavaScript', 'ES6'];
const descriptions = ['深度讲解JS数组操作', '实用代码片段分享'];
传统合并方法会存在重复元素:
javascript
const combined = [...titles, ...keywords, ...descriptions];
// 包含重复的'JavaScript'和'ES6'
二、Set方案:最简洁的现代语法
ES6引入的Set对象天然适合去重场景:
javascript
const uniqueItems = [...new Set([...titles, ...keywords, ...descriptions])];
优点分析:
- 代码量最少(只需一行)
- 时间复杂度O(n)
- 保持原始顺序
注意点:
- 无法直接处理对象数组(引用类型)
- 对大小写敏感('JS'和'js'会被视为不同)
三、filter+indexOf:兼容性方案
适用于需要支持旧版浏览器的项目:
javascript
const unionArrays = (...arrays) => {
const merged = [].concat(...arrays);
return merged.filter((item, index) => merged.indexOf(item) === index);
};
使用示例:
javascript
const result = unionArrays(titles, keywords, descriptions);
四、reduce方案:处理复杂数据结构
当需要根据对象属性去重时:
javascript
const articles = [
{id: 1, title: 'Vue3实战'},
{id: 2, title: 'React指南'},
{id: 1, title: 'Vue3实战'} // 重复项
];
const uniqueArticles = articles.reduce((acc, current) => {
const exists = acc.some(item => item.id === current.id);
return exists ? acc : [...acc, current];
}, []);
五、性能优化技巧
大数据量时(10万+元素)建议:
使用Map替代Set处理对象
javascript const uniqueByKey = (arr, key) => [ ...new Map(arr.map(item => [item[key], item])).values() ];
分块处理超大型数组
javascript const chunkProcess = (array, chunkSize = 10000) => { const result = []; for (let i = 0; i < array.length; i += chunkSize) { const chunk = array.slice(i, i + chunkSize); result.push(...[...new Set(chunk)]); } return [...new Set(result)]; };
六、实际应用场景
场景1:合并搜索结果
javascript
const mergeSearchResults = (localResults, apiResults) => {
const priorityMap = new Map();
// 本地结果优先
localResults.forEach(item => priorityMap.set(item.id, item));
// 补充API结果
apiResults.forEach(item => {
if (!priorityMap.has(item.id)) {
priorityMap.set(item.id, item);
}
});
return Array.from(priorityMap.values());
};
场景2:标签云生成
javascript
function generateTagCloud(...tagSources) {
const tagFrequency = new Map();
tagSources.flat().forEach(tag => {
const normalizedTag = tag.toLowerCase().trim();
tagFrequency.set(normalizedTag, (tagFrequency.get(normalizedTag) || 0) + 1);
});
return Array.from(tagFrequency.entries())
.sort((a, b) => b[1] - a[1])
.map(([tag]) => tag);
}
七、边界情况处理
处理null/undefined值:
javascript const safeUnion = (...arrays) => [ ...new Set(arrays.flat().filter(Boolean)) ];
自定义比较函数:
javascript const unionWith = (arrays, comparator) => { return arrays.flat().reduce((acc, current) => { const exists = acc.some(item => comparator(item, current)); return exists ? acc : [...acc, current]; }, []); };
八、TypeScript增强版
对于大型项目,建议使用类型安全的实现:
typescript
function union
const merged = ([] as T[]).concat(...arrays);
return [...new Set(merged)];
}
// 对象数组专用
function unionBy
const map = new Map<any, T>();
arrays.flat().forEach(item => {
if (!map.has(item[key])) {
map.set(item[key], item);
}
});
return Array.from(map.values());
}
九、常见问题解答
Q:如何保留最后出现的重复项?
javascript
function unionKeepLast(...arrays) {
const reversed = arrays.flat().reverse();
return [...new Set(reversed)].reverse();
}
Q:如何实现大小写不敏感的字符串去重?javascript
const caseInsensitiveUnion = (...arrays) => {
const lowerCaseSet = new Set();
const result = [];
arrays.flat().forEach(item => {
const lower = typeof item === 'string' ? item.toLowerCase() : item;
if (!lowerCaseSet.has(lower)) {
lowerCaseSet.add(lower);
result.push(item);
}
});
return result;
};
十、最佳实践建议
根据数据规模选择方案:
- 小数组(<1000项):任意方案均可
- 中等数组(1000-10万项):优先使用Set
- 超大数组(>10万项):考虑分块处理
项目环境考量:
- 现代浏览器:直接使用Set
- 需要兼容IE11:引入core-js polyfill
- Node.js环境:最新版本原生支持所有ES6+特性
代码可读性平衡:
- 团队项目应优先考虑代码清晰度
- 性能关键路径才进行深度优化