前端多个数组合并的多种方式
1. concat() 方法 - 不改变原数组
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [7, 8, 9]
const result1 = arr1.concat(arr2)
console.log(result1)
const result2 = arr1.concat(arr2, arr3)
console.log(result2)
const result3 = arr1.concat(4, 5, arr2)
console.log(result3)
console.log(arr1)
console.log(arr2)
2. 扩展运算符 Spread Operator (ES6+)
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [7, 8, 9]
const result1 = [...arr1, ...arr2]
console.log(result1)
const result2 = [...arr1, ...arr2, ...arr3]
console.log(result2)
const result3 = [0, ...arr1, 4, ...arr2, 7]
console.log(result3)
const result4 = [...arr1, ...arr2, ...arr3]
const result5 = arr1.concat(arr2, arr3)
console.log(result4)
3. push() 方法 - 原地修改
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [7, 8, 9]
Array.prototype.push.apply(arr1, arr2)
console.log(arr1)
arr1.push(...arr3)
console.log(arr1)
function mergeArraysInPlace(target, ...arrays) {
arrays.forEach(arr => {
target.push(...arr)
})
return target
}
const target = [1, 2, 3]
mergeArraysInPlace(target, [4, 5], [6, 7, 8])
console.log(target)
4. reduce() 方法
const arrays = [ [1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
const result1 = arrays.reduce((acc, curr) => acc.concat(curr), [])
console.log(result1)
const result2 = arrays.reduce((acc, curr) => [...acc, ...curr], [])
console.log(result2)
const arrays2 = [ [1, 2, 3],
[4, 5],
[6, 7, 8, 9]
]
const result3 = arrays2.reduce((acc, curr, index) => {
if (index % 2 === 0) {
return [...acc, ...curr]
}
return acc
}, [])
console.log(result3)
5. flat() 方法 (ES2019)
const nestedArrays = [ [1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
const result1 = nestedArrays.flat()
console.log(result1)
const deeplyNested = [ [1, 2],
[3, [4, 5]],
[[6], [7, 8, 9]]
]
const result2 = deeplyNested.flat(Infinity)
console.log(result2)
const result3 = deeplyNested.flat(2)
console.log(result3)
6. 对象数组合并(根据ID等)
// 根据ID合并对象数组
const arr1 = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 }
]
const arr2 = [
{ id: 2, city: 'New York', job: 'Engineer' },
{ id: 3, city: 'London', job: 'Designer' },
{ id: 4, city: 'Tokyo', job: 'Developer' }
]
// 方法1: 使用 Map
function mergeObjectArrays(arr1, arr2, key = 'id') {
const map = new Map()
// 合并所有对象
;[...arr1, ...arr2].forEach(item => {
const itemKey = item[key]
if (map.has(itemKey)) {
// 合并相同key的对象
map.set(itemKey, { ...map.get(itemKey), ...item })
} else {
map.set(itemKey, item)
}
})
return Array.from(map.values())
}
const merged1 = mergeObjectArrays(arr1, arr2, 'id')
console.log(merged1)
/*
[
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30, city: 'New York', job: 'Engineer' },
{ id: 3, name: 'Charlie', age: 35, city: 'London', job: 'Designer' },
{ id: 4, city: 'Tokyo', job: 'Developer' }
]
*/
// 方法2: 使用 reduce
const merged2 = [...arr1, ...arr2].reduce((acc, obj) => {
const existing = acc.find(item => item.id === obj.id)
if (existing) {
Object.assign(existing, obj)
} else {
acc.push(obj)
}
return acc
}, [])
7. 数组合并并去重
// 合并并去重
const arr1 = [1, 2, 3, 4, 5]
const arr2 = [4, 5, 6, 7, 8]
const arr3 = [7, 8, 9, 10]
// 方法1: Set
const result1 = [...new Set([...arr1, ...arr2, ...arr3])]
console.log(result1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 方法2: filter
const result2 = arr1.concat(
arr2.filter(item => !arr1.includes(item)),
arr3.filter(item => !arr1.includes(item) && !arr2.includes(item))
)
console.log(result2) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 方法3: reduce
const allArrays = [arr1, arr2, arr3]
const result3 = allArrays.reduce((acc, curr) => {
curr.forEach(item => {
if (!acc.includes(item)) {
acc.push(item)
}
})
return acc
}, [])
console.log(result3) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 对象数组去重合并
const objArr1 = [{id: 1}, {id: 2}]
const objArr2 = [{id: 2}, {id: 3}]
const mergedObjArray = [...objArr1, ...objArr2].reduce((acc, obj) => {
if (!acc.some(item => item.id === obj.id)) {
acc.push(obj)
}
return acc
}, [])
console.log(mergedObjArray) // [{id: 1}, {id: 2}, {id: 3}]
8. 异步数组合并(Promise)
async function mergeAsyncArrays() {
const getArray1 = () => Promise.resolve([1, 2, 3])
const getArray2 = () => Promise.resolve([4, 5, 6])
const getArray3 = () => Promise.resolve([7, 8, 9])
const [arr1, arr2, arr3] = await Promise.all([
getArray1(),
getArray2(),
getArray3()
])
const result1 = [...arr1, ...arr2, ...arr3]
console.log('方法1:', result1)
const result2 = []
const arrays = [getArray1, getArray2, getArray3]
for (const getArray of arrays) {
const arr = await getArray()
result2.push(...arr)
}
console.log('方法2:', result2)
const result3 = await arrays.reduce(async (accPromise, getArray) => {
const acc = await accPromise
const arr = await getArray()
return [...acc, ...arr]
}, Promise.resolve([]))
console.log('方法3:', result3)
return result1
}
mergeAsyncArrays()
9. Vue 3 响应式数组合并
<template>
<div>
<h3>数组1: {{ array1 }}</h3>
<h3>数组2: {{ array2 }}</h3>
<h3>合并结果: {{ mergedArray }}</h3>
<button @click="addToArray1">向数组1添加</button>
<button @click="addToArray2">向数组2添加</button>
<button @click="mergeArrays">合并数组</button>
<button @click="reset">重置</button>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const array1 = ref([1, 2, 3])
const array2 = ref([4, 5, 6])
const mergedArray = computed(() => [...array1.value, ...array2.value])
const manualMerge = ref([])
const mergeArrays = () => {
manualMerge.value = [...array1.value, ...array2.value]
}
const addToArray1 = () => {
array1.value.push(array1.value.length + 1)
}
const addToArray2 = () => {
array2.value.push(array2.value.length + 4)
}
const reset = () => {
array1.value = [1, 2, 3]
array2.value = [4, 5, 6]
manualMerge.value = []
}
watch([array1, array2], () => {
console.log('数组变化,自动合并:', [...array1.value, ...array2.value])
}, { deep: true })
</script>
10. 性能优化的大数组合并
class ArrayMerger {
static mergeTypedArrays(arrays) {
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0)
const result = new Uint8Array(totalLength)
let offset = 0
for (const arr of arrays) {
result.set(arr, offset)
offset += arr.length
}
return result
}
static *mergeStreaming(arrays) {
for (const arr of arrays) {
for (const item of arr) {
yield item
}
}
}
static mergeLargeArrays(arrays, chunkSize = 10000) {
const result = []
for (const arr of arrays) {
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize)
result.push(...chunk)
}
}
return result
}
}
const largeArray1 = new Uint8Array(1000000).fill(1)
const largeArray2 = new Uint8Array(1000000).fill(2)
console.time('mergeTypedArrays')
const merged = ArrayMerger.mergeTypedArrays([largeArray1, largeArray2])
console.timeEnd('mergeTypedArrays')
console.log('合并后长度:', merged.length)
const arrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
const streamResult = Array.from(ArrayMerger.mergeStreaming(arrays))
console.log('流式合并:', streamResult)
11. 多维数组合并
// 多维数组合并
const matrix1 = [
[1, 2],
[3, 4]
]
const matrix2 = [
[5, 6],
[7, 8]
]
// 水平合并(增加列)
function mergeHorizontally(matrix1, matrix2) {
return matrix1.map((row, i) => [...row, ...(matrix2[i] || [])])
}
console.log('水平合并:')
console.log(mergeHorizontally(matrix1, matrix2))
// [[1, 2, 5, 6], [3, 4, 7, 8]]
// 垂直合并(增加行)
function mergeVertically(matrix1, matrix2) {
return [...matrix1, ...matrix2]
}
console.log('垂直合并:')
console.log(mergeVertically(matrix1, matrix2))
// [[1, 2], [3, 4], [5, 6], [7, 8]]
// 深度合并
const deepArray1 = [[[1, 2], [3, 4]], [[5, 6]]]
const deepArray2 = [[[7, 8]], [[9, 10], [11, 12]]]
function deepMergeArrays(arr1, arr2) {
if (Array.isArray(arr1[0]) && Array.isArray(arr2[0])) {
// 如果都是数组,递归合并
return arr1.map((subArr, i) =>
deepMergeArrays(subArr, arr2[i] || [])
)
} else {
// 否则直接合并
return [...arr1, ...arr2]
}
}
console.log('深度合并:')
console.log(deepMergeArrays(deepArray1, deepArray2))
12. 实用工具函数
class ArrayMergeUtils {
static merge(...arrays) {
return [].concat(...arrays)
}
static deepMerge(...arrays) {
return arrays.reduce((acc, curr) => {
if (Array.isArray(curr)) {
return [...acc, ...this.deepMerge(...curr)]
}
return [...acc, curr]
}, [])
}
static mergeByCondition(arrays, condition) {
return arrays.reduce((acc, curr, index) => {
if (condition(curr, index, arrays)) {
return [...acc, ...curr]
}
return acc
}, [])
}
static mergeInterleave(...arrays) {
const maxLength = Math.max(...arrays.map(arr => arr.length))
const result = []
for (let i = 0; i < maxLength; i++) {
for (const arr of arrays) {
if (i < arr.length) {
result.push(arr[i])
}
}
}
return result
}
static mergeInGroups(arrays, groupSize = 2) {
const result = []
for (let i = 0; i < arrays.length; i += groupSize) {
const group = arrays.slice(i, i + groupSize)
const merged = this.merge(...group)
result.push(merged)
}
return result
}
}
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [7, 8, 9]
console.log('基本合并:', ArrayMergeUtils.merge(arr1, arr2, arr3))
console.log('交错合并:', ArrayMergeUtils.mergeInterleave(arr1, arr2, arr3))
console.log('按条件合并:',
ArrayMergeUtils.mergeByCondition([arr1, arr2, arr3], (arr, index) => index % 2 === 0)
)
const allArrays = [arr1, arr2, arr3, [10, 11, 12]]
console.log('分组合并:', ArrayMergeUtils.mergeInGroups(allArrays, 2))
13. TypeScript 泛型版本
class ArrayMergerTS {
static merge<T>(...arrays: T[][]): T[] {
return ([] as T[]).concat(...arrays)
}
static mergeUnique<T>(...arrays: T[][]): T[] {
return Array.from(new Set(this.merge(...arrays)))
}
static mergeObjectsByKey<T extends Record<string, any>>(
arrays: T[][],
key: keyof T
): T[] {
const map = new Map<any, T>()
arrays.flat().forEach(item => {
const itemKey = item[key]
if (map.has(itemKey)) {
map.set(itemKey, { ...map.get(itemKey)!, ...item })
} else {
map.set(itemKey, item)
}
})
return Array.from(map.values())
}
static mergeIf<T>(
arrays: T[][],
predicate: (item: T, index: number, array: T[]) => boolean
): T[] {
return arrays.reduce((acc, curr) => {
const filtered = curr.filter(predicate)
return [...acc, ...filtered]
}, [] as T[])
}
}
const nums1: number[] = [1, 2, 3]
const nums2: number[] = [4, 5, 6]
const mergedNums = ArrayMergerTS.merge(nums1, nums2)
const objArr1 = [{ id: 1, name: 'Alice' }]
const objArr2 = [{ id: 1, age: 25 }, { id: 2, name: 'Bob' }]
const mergedObjs = ArrayMergerTS.mergeObjectsByKey([objArr1, objArr2], 'id')
总结
常用方法对比:
| 方法 | 是否修改原数组 | 性能 | 适用场景 |
|---|
concat() | ❌ 不修改 | 良好 | 基本合并,兼容性好 |
扩展运算符 ... | ❌ 不修改 | 良好 | ES6+,代码简洁 |
push(...arr) | ✅ 修改 | 良好 | 原地合并,修改原数组 |
reduce() | 取决于实现 | 一般 | 复杂合并逻辑 |
flat() | ❌ 不修改 | 良好 | 多维数组合并 |
选择建议:
- 简单合并:使用扩展运算符
[...arr1, ...arr2]
- 兼容性要求:使用
concat()
- 原地修改:使用
push(...arr)
- 多维合并:使用
flat()
- 对象合并:使用
Map或 reduce
- 大数组合并:分块处理或使用类型化数组
- 去重合并:使用
Set