1

I would like to combine elements of 2 arrays based on the name. For example:

Array1 = [
  {name: "name1", language: "lang1"}, 
  {name: "name2", language: "lang2"}, 
  {name: "name3", language: "lang3"}]

Array2 = [
  {name: "name1", subject: "sub1"}, 
  {name: "name2", subject: "sub2"}, 
  {name: "name3", subject: "sub3"}]

I need to generate the following array:

Array3 = [
  {language: "lang1", subject: "sub1"}, 
  {language: "lang2", subject: "sub2"}, 
  {language: "lang3", subject: "sub3"}]

The logic I could think of was to write an explicit for loop to compare every element of first array with every element of second array and check if name matches as shown below.

let Array3 = []
for(let i=0;i<Array1.length;i++)
{
    let elem = Array1[i];
    for(let j=0;j<Array2.length;j++)
    {
        if(Array2[j].name===elem.name)
        {
            Array3.append({language: elem.language, subject: Array2[j].subject})
            break;
        }
    }
}

However, my actual dataset is quite large and this seems inefficient. How can this can be achieved in a more efficient manner (like using higher order functions or something)?

Dev5
  • 449
  • 3
  • 15
  • 1
    `The logic I could think of was to write an explicit for loop` please include this attempt in the question. – Olian04 Sep 19 '20 at 17:40
  • @Olian04 edited to include my code. It is not that good which is why I didn't add it in the beginning itself – Dev5 Sep 19 '20 at 17:50

3 Answers3

2

You need to iterate over the two arrays and group the generated object in a map having the name as the key:

let Array1 = [
     {name: "name1", language: "lang1"}, 
     {name: "name2", language: "lang2"}, 
     {name: "name3", language: "lang3"}
];
let Array2 = [
     {name: "name1", subject: "sub1"}, 
     {name: "name2", subject: "sub2"}, 
     {name: "name3", subject: "sub3"}
];
               
let map = new Map();
Array1.forEach(e => map.set(e.name, {language: e.language}));
Array2.forEach(e => {
     if(map.has(e.name))
          map.set(e.name, {...map.get(e.name), subject: e.subject});
});
let Array3 = [...map.values()].filter(e => e.language && e.subject);

console.log(Array3);
Majed Badawi
  • 27,616
  • 4
  • 25
  • 48
2

Using a Map for O(1) lookup of one of the arrays using name as key lets you iterate each array only once.

const Array1=[{name:"name1",language:"lang1"},{name:"name2",language:"lang2"},{name:"name3",language:"lang3"}],Array2=[{name:"name1",subject:"sub1"},{name:"name2",subject:"sub2"},{name:"name3",subject:"sub3"}];
  
const a1Map = new Map(Array1.map(({name, ...r})=> [name, {...r}]));
const res = Array2.map(({name, ...r}) => ({...r, ...a1Map.get(name)}))

console.log(res)
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • This looks nice ,Thanks but could you modify it so that result is exactly like in the question. (I don't want the name in my result array) – Dev5 Sep 19 '20 at 18:07
  • Added some destructuring to remove name in final results. don't need to know any of the property names other than `name` – charlietfl Sep 19 '20 at 18:11
-1

Yes you are thinking in right order , you need to use the sort algorithm logics , I will say nested for loops will be just as good. With larger dataset , since you need to extract the values from two different array you can use the nested for loops.

 for(int i=0;i>array1.length();i++){
  This can be use for first array
  Define String x=",";
  For second
  for(int j=0;j>array2.length();j++)
  {
    Check if ( (","+j+",").contains(x)) then break;
    If array1 name found in array 2, store array3 as you want 
    Also Store value of j in x
    Like x=x +j+",";
   }}

This way your nested for loop will skip the comparison code. Above algo is raw but will reduce the complexity a significant bit.

charlietfl
  • 170,828
  • 13
  • 121
  • 150