简体   繁体   中英

Merge two javascript maps by comparing their keys

i want to merge two Maps:

const map1 = new Map([
  [1, {title: 't1', name: 'nam1'}],
  [2, {title: 't2', name: 'nam2'}]
])



const map2 = new Map([
  [1, {value: 'v1', progress: 20}],
  [2, {value: 'v2', progress: 100}]
])



const commonMap = new Map()

so the new Map should look like

const commonMap = new Map([
  [1, {title: 't1', name: 'nam1', value: 'v1', progress: 20}],
  [2, {title: 't2', name: 'nam2', value: 'v2', progress: 100}]
])

How to achieve this?

You could iterate the maps and reduce a new map.

 const map1 = new Map([[1, { title: 't1', name: 'nam1' }], [2, { title: 't2', name: 'nam2' }]]), map2 = new Map([[1, { value: 'v1', progress: 20 }], [2, { value: 'v2', progress: 100 }]]), mergedMap = [...map1, ...map2].reduce((m, [k, v]) => m.set(k, {...m.get(k), ... v }), new Map); console.log([...mergedMap]);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Traverse newly created key-value pair array from both map and set it into the new map.

 const map1 = new Map([ [1, { title: 't1', name: 'nam1' }], [2, { title: 't2', name: 'nam2' }], ]); const map2 = new Map([ [1, { value: 'v1', progress: 20 }], [2, { value: 'v2', progress: 100 }], ]); const commonMap = new Map(); [...map1, ...map2].forEach(([x, y]) => commonMap.set(x, commonMap.has(x)? {...commonMap.get(x), ...y }: {...y }) ); console.log([...commonMap]);

Interesting no one suggested this solution, but this is one other method:

 const map1 = new Map([ [1, {title: 't1', name: 'nam1'}], [2, {title: 't2', name: 'nam2'}] ]); const map2 = new Map([ [1, {value: 'v1', progress: 20}], [2, {value: 'v2', progress: 100}] ]) const commonMap = new Map(map1); map2.forEach((obj, k) => commonMap.set(k, {...obj, ...commonMap.get(k)})); console.log(...commonMap);

Since the Map constructor takes any iterable, you can use a generator function that takes the maps and an optional merge strategy for values. Then iterate over the keys and use the merge strategy to combine the values. By default, you can just merge two objects:

 const defaultMerge = (...xs) => Object.assign({}, ...xs); function* mapMerge(map1, map2, mergeFn = defaultMerge) { for (const [key, value1] of map1.entries()) { const value2 = map2.get(key); yield [key, mergeFn(value1, value2)]; } } const map1 = new Map([ [1, {title: 't1', name: 'nam1'}], [2, {title: 't2', name: 'nam2'}] ]) const map2 = new Map([ [1, {value: 'v1', progress: 20}], [2, {value: 'v2', progress: 100}] ]) const commonMap = new Map(mapMerge(map1, map2)); //display for StackSnippets for(const [key, value] of commonMap.entries()) { console.log(key, "->", value); } console.log("--- custom merge ---"); const customMergecommonMap = new Map(mapMerge( map1, map2, (a, b) => ({title: a.title, value: b.value}) )); //display for StackSnippets for(const [key, value] of customMergecommonMap.entries()) { console.log(key, "->", value); }

This can be generalised for any amount of maps and the ability to handle maps with potentially different keys. Assuming the intention is to merge only existing values, then it can be done like this:

 const defaultMerge = (...xs) => Object.assign({}, ...xs); function* mapMerge(...maps) { let mergeFn = defaultMerge; if (typeof maps[maps.length - 1] === "function") { //if a merge function was passed mergeFn = maps.pop(); } //collect all keys from all maps in case of differences const allKeys = new Set( maps.flatMap(m => Array.from(m.keys())) ); for (const key of allKeys) { const values = maps.filter(m => m.has(key)) //only maps with this key.map(m => m.get(key)); //get the value yield [key, mergeFn(...values)]; } } const map1 = new Map([ [1, {title: 't1', name: 'nam1'}], [2, {title: 't2', name: 'nam2'}] ]) const map2 = new Map([ [1, {value: 'v1', progress: 20}], [2, {value: 'v2', progress: 100}] ]) const commonMap = new Map(mapMerge(map1, map2)); //display for StackSnippets for(const [key, value] of commonMap.entries()) { console.log(key, "->", value); } console.log("--- custom merge ---"); const customMergecommonMap = new Map(mapMerge( map1, map2, (a, b) => ({title: a.title, value: b.value}) )); //display for StackSnippets for(const [key, value] of customMergecommonMap.entries()) { console.log(key, "->", value); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM