javascript - 根據鍵合併兩個物件陣列
我有兩個陣列:
陣列 1:
[
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
]
以及陣列 2:
[
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
]
我需要根據 id 合併這兩個陣列,並得到以下結果:
[
{ id: "abdc4051", date: "2017-01-24", name: "ab" },
{ id: "abdc4052", date: "2017-01-22", name: "abc" }
]
我如何在不遍歷 Object.keys 的情況下做到這一點?
答案#1
你可以這樣做 -
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let arr3 = arr1.map((item, i) => Object.assign({}, item, arr2[i]));
console.log(arr3);如果 arr1 和 arr2 的順序不同,請使用以下程式碼:
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let merged = [];
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...(arr2.find((itmInner) => itmInner.id === arr1[i].id))}
);
}
console.log(merged);如果 arr1 和 arr2 順序相同,請使用此方法
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let merged = [];
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...arr2[i]
});
}
console.log(merged);答案#2
這個解決方案即使在合併的陣列大小不同時也適用。此外,即使匹配的鍵名稱不同,也適用。
使用 Map 將兩個陣列合併,如下所示:
const arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4053", date: "2017-01-22" }
];
const arr2 = [
{ nameId: "abdc4051", name: "ab" },
{ nameId: "abdc4052", name: "abc" }
];
const map = new Map();
arr1.forEach(item => map.set(item.id, item));
arr2.forEach(item => map.set(item.nameId, {...map.get(item.nameId), ...item}));
const mergedArr = Array.from(map.values());
console.log(JSON.stringify(mergedArr));.as-console-wrapper { max-height: 100% !important; top: 0; }運行堆疊程式碼片段來查看結果:
[
{
"id": "abdc4051",
"date": "2017-01-24",
"nameId": "abdc4051",
"name": "ab"
},
{
"id": "abdc4052",
"date": "2017-01-22",
"nameId": "abdc4052",
"name": "abc"
},
{
"id": "abdc4053",
"date": "2017-01-22"
}
]
答案#3
你可以在一行中完成這個
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
const mergeById = (a1, a2) =>
a1.map(itm => ({
...a2.find((item) => (item.id === itm.id) && item),
...itm
}));
console.log(mergeById(arr1, arr2));- 對 array1 進行映射
- 在 array2 中搜尋 array1.id
- 如果你找到它……將 array2 的結果展開到 array1 中
最終的陣列將只包含兩個陣列中匹配的 id
答案#4
這裡有一個使用 reduce 和 Object.assign 的 O(n) 解法
const joinById = ( ...lists ) =>
Object.values(
lists.reduce(
( idx, list ) => {
list.forEach( ( record ) => {
if( idx[ record.id ] )
idx[ record.id ] = Object.assign( idx[ record.id ], record)
else
idx[ record.id ] = record
} )
return idx
},
{}
)
)
要在原作者的案例中使用此功能,將你想要合併的陣列傳入 joinById(注意 lists 是一個剩餘參數)。
let joined = joinById(list1, list2)
每個列表都會縮減為單一對象,其中鍵是 ID,值是對象。如果在給定的鍵上已經有值,則會對其調用 object.assign 並與當前記錄合併。
這裡是一個通用的 O(n*m) 解法,其中 n 是記錄數,m 是鍵的數量。這只適用於有效的物件鍵。如果需要,你可以將任何值轉換為 base64 並使用它。
const join = ( keys, ...lists ) =>
lists.reduce(
( res, list ) => {
list.forEach( ( record ) => {
let hasNode = keys.reduce(
( idx, key ) => idx && idx[ record[ key ] ],
res[ 0 ].tree
)
if( hasNode ) {
const i = hasNode.i
Object.assign( res[ i ].value, record )
res[ i ].found++
} else {
let node = keys.reduce( ( idx, key ) => {
if( idx[ record[ key ] ] )
return idx[ record[ key ] ]
else
idx[ record[ key ] ] = {}
return idx[ record[ key ] ]
}, res[ 0 ].tree )
node.i = res[ 0 ].i++
res[ node.i ] = {
found: 1,
value: record
}
}
} )
return res
},
[ { i: 1, tree: {} } ]
)
.slice( 1 )
.filter( node => node.found === lists.length )
.map( n => n.value )
這基本上與 joinById 方法相同,除了它保留一個索引對象來識別要連接的記錄。這些記錄被存儲在數組中,索引存儲了給定鍵集的記錄位置以及它被發現的列表數量。
每次遇到相同的鍵集合時,它會在樹中找到該節點,更新其索引處的元素,並增加其被找到的次數。
加入後,idx 物件會使用 slice 從陣列中移除,並且任何在每個集合中未找到的元素也會被移除。這使它成為內部連接,你可以移除這個過濾器來取得完整外部連接。
最後,每個元素都映射到它的值,然後你就得到了合併的陣列。
答案#5
你可以使用任意數量的陣列,並在相同的索引上映射新的物件。
var array1 = [{ id: "abdc4051", date: "2017-01-24" }, { id: "abdc4052", date: "2017-01-22" }],
array2 = [{ id: "abdc4051", name: "ab" }, { id: "abdc4052", name: "abc" }],
result = [array1, array2].reduce((a, b) => a.map((c, i) => Object.assign({}, c, b[i])));
console.log(result);.as-console-wrapper { max-height: 100% !important; top: 0; }答案#6
如果你有兩個陣列需要根據值合併,即使它們的順序不同
let arr1 = [
{ id:"1", value:"this", other: "that" },
{ id:"2", value:"this", other: "that" }
];
let arr2 = [
{ id:"2", key:"val2"},
{ id:"1", key:"val1"}
];
你可以這樣做
const result = arr1.map(item => {
const obj = arr2.find(o => o.id === item.id);
return { ...item, ...obj };
});
console.log(result);
答案#7
假設兩個陣列長度相等,要在 id 上合併這兩個陣列:
arr1.map(item => ({
...item,
...arr2.find(({ id }) => id === item.id),
}));
