I am trying to find out the best / most efficient or most functional way to compare / merge / manipulate two arrays (lists) simultaneously in JS.
The example I give below is a simple example of the overall concept. In my current project, I deal with some very crazy list mapping, filtering, etc. with very large lists of objects.
As delinated below, my first idea (version1
) on comparing lists would be to run through the first list (i.e. map), and in the anonymous/callback function, filter the second list to meet the criteria needed for the compare (match ids for example). This obviously works, as per version1
below.
I had a question performance-wise, as by this method on every iteration/call of map, the entire 2nd list gets filtered just to find that one item that matches the filter.
Also, the filter passes every other item in list2 which should be matched in list1. Meaning (as that sentence probably did not make sense):
list1.map list2.filter id:1 [id:3,id:2,id:1] ^-match id:2 [id:3,id:2,id:1] ^-match id:3 [id:3,id:2,id:1] ^-match
Ideally on the first iteration of map (
list1 id:1
), when the filter encounterslist2 id:3
(first item) it would just match it tolist1 id:3
Thinking with the above concept (matching to a later id when it is encountered earlier, I came up with version2
).
This makes list2 into a dictionary, and then looks up the value in any sequence by key.
const list1 = [
{id: '1',init:'init1'},
{id: '2',init:'init2'},
{id: '3',init:'init3'}
];
const list2 = [
{id: '2',data:'data2'},
{id: '3',data:'data3'},
{id: '4',data:'data4'}
];
/* ---------
* version 1
*/
const mergedV1 = list1.map(n => (
{...n,...list2.filter(f => f.id===n.id)[0]}
));
/* [
{"id": "1", "init": "init1"},
{"id": "2", "init": "init2", "data": "data2"},
{"id": "3", "init": "init3", "data": "data3"}
] */
/* ---------
* version 2
*/
const dictList2 = list2.reduce((dict,item) => (dict[item.id]=item,dict),{});
// does not handle duplicate ids but I think that's
// outside the context of this question.
const mergedV2 = list1.map(n => ({...n,...dictList2[n.id]}));
/* [
{"id": "1", "init": "init1"},
{"id": "2", "init": "init2", "data": "data2"},
{"id": "3", "init": "init3", "data": "data3"}
] */
JSON.stringify(mergedV1) === JSON.stringify(mergedV2);
// true
// and just for fun
const sqlLeftOuterJoinInJS = list1 => list2 => on => {
const dict = list2.reduce((dict,item) => (
dict[item[on]]=item,dict
),{});
return list1.map(n => ({...n,...dict[n[on]]}
))};
Obviously the above examples are pretty simple (merging two lists, each list having a length of 3). There are more complex instances that I am working with.
I don't know if there are some smarter (and ideally functional) techniques out there that I should be using.