lodash数组拼接:concat与union合并数组
在日常开发中,数组拼接是常见的操作,但不同的合并方式会产生截然不同的结果。你是否遇到过合并数组时出现重复元素的问题?或者需要深度合并多层数组却不知从何下手?本文将详细对比lodash中的concat和union两个数组合并方法,帮助你在不同场景下选择最合适的工具。读完本文后,你将能够:掌握两种合并方法的核心差异、解决重复元素问题、处理特殊数据类型合并,并通过实际案例优化代码性能。
核心方法对比
concat方法:灵活的浅合并工具
concat方法是lodash中最基础的数组合并工具,它能够将多个数组或值拼接成一个新数组。与原生JavaScript的Array.prototype.concat相比,lodash的concat提供了更好的兼容性和一致性。
基础用法:
// 简单数组拼接
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const result = _.concat(arr1, arr2);
// 结果: [1, 2, 3, 4, 5, 6]
// 混合值类型拼接
const result = _.concat([1], 2, [3], [[4]]);
// 结果: [1, 2, 3, [4]]
从test/concat.spec.js的测试用例可以看出,concat具有以下特性:
- 不会修改原数组,而是返回一个全新的数组
- 能够处理非数组值,会将其作为单个元素添加
- 对稀疏数组(sparse array)会被视为密集数组处理
- 只进行浅层次的合并,不会递归展开嵌套数组
union方法:自动去重的合并工具
union方法则专注于合并多个数组并自动去除重复元素。它内部使用了baseUniq方法来确保结果数组中的元素唯一性。
源码解析:
import baseFlatten from './.internal/baseFlatten.js';
import baseUniq from './.internal/baseUniq.js';
import isArrayLikeObject from './isArrayLikeObject.js';
function union(...arrays: any[]) {
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
}
export default union;
src/union.ts中的实现展示了union的工作流程:
- 使用
baseFlatten将输入的多个数组展平一层 - 通过
baseUniq方法去除重复元素 - 只处理类数组对象(array-like object)
基础用法:
// 基本去重合并
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
const result = _.union(arr1, arr2);
// 结果: [1, 2, 3, 4, 5]
// 多数组合并
const result = _.union([1, 2], [2, 3], [3, 4]);
// 结果: [1, 2, 3, 4]
实战场景对比
场景一:保留所有元素(包括重复项)
当你需要合并数组并保留所有元素,包括重复项时,concat是理想选择:
// 合并购物车商品(允许重复商品)
const cart1 = ['apple', 'banana'];
const cart2 = ['banana', 'orange'];
const combinedCart = _.concat(cart1, cart2);
// 结果: ['apple', 'banana', 'banana', 'orange']
场景二:确保元素唯一性
当需要合并多个数组并自动去重时,union更适合:
// 合并用户标签并去重
const tags1 = ['frontend', 'javascript'];
const tags2 = ['javascript', 'lodash'];
const uniqueTags = _.union(tags1, tags2);
// 结果: ['frontend', 'javascript', 'lodash']
场景三:处理嵌套数组
concat和union都只会展平一层嵌套数组,对于深层嵌套需要配合其他方法:
// concat处理嵌套数组
const resultConcat = _.concat([1], [2, [3]], [[4]]);
// 结果: [1, 2, [3], [4]]
// union处理嵌套数组
const resultUnion = _.union([1, [2]], [[2], 3]);
// 结果: [1, [2], 3] (注意[2]被视为唯一元素)
如果需要深度展平数组,可以结合使用flatten方法:
// 深度展平后合并去重
const arr1 = [1, [2, [3]]];
const arr2 = [3, [4]];
const result = _.union(_.flattenDeep(arr1), _.flattenDeep(arr2));
// 结果: [1, 2, 3, 4]
性能对比与优化
在处理大型数组时,选择合适的方法对性能至关重要:
| 操作场景 | concat | union |
|---|---|---|
| 简单合并 | 快(O(n)) | 较慢(O(n log n) 由于去重) |
| 去重合并 | 需要额外去重步骤 | 内置去重功能 |
| 内存占用 | 低 | 较高(需要存储唯一值索引) |
优化建议:
- 当处理大型数组且不需要去重时,优先使用
concat - 如需去重,
union比concat+uniq组合更高效 - 对于嵌套数组,考虑使用
unionBy或unionWith进行自定义去重
常见问题与解决方案
问题一:合并对象数组时的去重问题
union方法使用严格相等(===)比较元素,对于对象数组无法正确去重:
// 对象数组去重失败
const arr1 = [{ id: 1 }, { id: 2 }];
const arr2 = [{ id: 2 }, { id: 3 }];
const result = _.union(arr1, arr2);
// 结果: [{ id: 1 }, { id: 2 }, { id: 2 }, { id: 3 }]
解决方案:使用unionBy或unionWith:
// 使用unionBy按id去重
const result = _.unionBy(arr1, arr2, 'id');
// 结果: [{ id: 1 }, { id: 2 }, { id: 3 }]
问题二:处理复杂数据类型
当需要合并包含null、undefined等特殊值的数组时:
// 包含特殊值的数组合并
const arr1 = [null, undefined, 0, false];
const arr2 = [undefined, null, true, 0];
const resultConcat = _.concat(arr1, arr2);
const resultUnion = _.union(arr1, arr2);
// concat结果: [null, undefined, 0, false, undefined, null, true, 0]
// union结果: [null, undefined, 0, false, true]
总结与最佳实践
方法选择指南
| 需求场景 | 推荐方法 | 时间复杂度 |
|---|---|---|
| 简单合并,保留重复项 | concat | O(n) |
| 合并并去重基本类型 | union | O(n log n) |
| 按属性去重对象数组 | unionBy | O(n log n) |
| 自定义规则去重 | unionWith | O(n log n) |
| 深度合并嵌套数组 | concat + flattenDeep | O(n) |
性能优化技巧
- 当处理大量数据时,考虑先合并再去重,而非多次调用
union - 对于已知不会有重复项的场景,优先使用
concat - 处理对象数组时,使用
unionBy指定唯一键,避免全对象比较 - 对于大型数组,考虑分块处理以避免内存问题
掌握concat和union的使用场景和差异,能够帮助你在实际开发中写出更高效、更清晰的代码。根据具体需求选择合适的方法,既能保证功能正确性,又能优化性能。lodash还提供了unionBy、unionWith等变体方法,满足更复杂的合并需求,建议结合官方文档深入学习。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



