Roster
Roster

Reputation: 1944

Update an array using another array based on matched property value

I have two arrays like this

 let array1 =   [{
      'id': 1,
      'name': 'A'
    }, {
      'id': 2,
      'name': 'B'
    }, {
      'id': 3,
      'name': 'C'
    }]

let array2 =   [{
      'id': 1,
      'name': 'x'
    }, {
      'id': 2,
      'name': 'y'
    }]

I want to update array 1 with the array 2 object values which are matching based on id values. Result would be something like this.

 [{
      'id': 1,
      'name': 'x'
    }, {
      'id': 2,
      'name': 'y'
    }, {
      'id': 3,
      'name': 'C'
    }]

I have written something like this but not working .

    array1.forEach(item1 => {
        const itemFromArr2 = array2.find(item2 => item2.id== item1.id);
        if (itemFromArr2) {
           item1= itemFromArr2;
        }
     }
  )

Please suggest me how to do this.

Upvotes: 1

Views: 1507

Answers (4)

Ori Drori
Ori Drori

Reputation: 191946

Convert the update array to a Map, then iterate the target array with Array.map(), and merge it with the object of the same key in the upateMap if it exists:

const fn = (predicate, target, update) => {
  const updateMap = new Map(update.map(o => [predicate(o), o]))
  
  return target.map(o => {
    const key = predicate(o)
    
    return updateMap.has(key)
      ? { ...o, ...updateMap.get(key)}
      : o
  })
}

const array1 = [{"id":1,"name":"A"},{"id":2,"name":"B"},{"id":3,"name":"C"}]
const array2 = [{"id":1,"name":"x"},{"id":2,"name":"y"}]

const result = fn(o => o.id, array1, array2);
console.log(result);

With types (TS playground):

const fn = <T>(predicate: (arg: T) => any, target: T[], update: T[]) => {
  const updateMap = new Map(update.map(o => [predicate(o), o]))
  
  return target.map(o => {
    const key = predicate(o)
    
    return updateMap.has(key)
      ? { ...o, ...updateMap.get(key)}
      : o
  })
}

Upvotes: 1

user13258211
user13258211

Reputation:

Here's a solution using Generics:

const array1 =   [{
      'id': 1,
      'name': 'A'
    }, {
      'id': 2,
      'name': 'B'
    }, {
      'id': 3,
      'name': 'C'
    }]

const array2 =   [{
      'id': 1,
      'name': 'x'
    }, {
      'id': 2,
      'name': 'y'
    }]


function mergeArray<T>(arr1: T[], arr2: T[], identifier: keyof T): T[] {
    for(const oItem of arr2){
        const itemInArr1 = 
            arr1.find(item => item[identifier] === oItem[identifier]);
        if(itemInArr1){
            for(const key in itemInArr1){
                itemInArr1[key] = oItem[key];
            }
        } else {
            arr1.push(oItem);
        }
    }
    return arr1;
}

console.log(mergeArray(array1,array2, 'id'));

Playground

This iterates over the itmes in array2and checks their existence inside array1 based on the identifier.

Based on whether or not the item exists in array1, the item will be modified, or the item from array2 is pushed into array1.

Upvotes: 0

ikhvjs
ikhvjs

Reputation: 5937

Using a hashmap to update the array.

The reason of hashmap is for performance.

const array1 = [
    { id: 1, name: "A" },
    { id: 2, name: "B" },
    { id: 3, name: "C" },
];

const array2 = [
    { id: 1, name: "x" },
    { id: 2, name: "y" },
];

const hashMap2 = array2.reduce((carry, item) => {
    const { id } = item;
    if (!carry[id]) {
        carry[id] = item;
    }
    return carry;
}, {});

const output = array1.map(item => {
    const newName = hashMap2[item.id]?.name;
    if (newName) {
        item.name = newName;
    }
    return item;
});

console.log(output);

Upvotes: 0

stacj
stacj

Reputation: 1121

You might want to check this one-liner out:

array1.map(e => (e.name = array2.find(a => a.id == e.id)?.name || e.name, e));

Explanation: We are mapping over array1 and searching for the matching id in array2, if it is found (array2.find(a => a.id == e.id)?.name), we override the name property (e.name = ...), otherwise we keep it as it is (... || e.name).

Small example:

let array1 = [{
  'id': 1,
  'name': 'A'
}, {
  'id': 2,
  'name': 'B'
}, {
  'id': 3,
  'name': 'C'
}]

let array2 = [{
  'id': 1,
  'name': 'x'
}, {
  'id': 2,
  'name': 'y'
}]

const newarray = array1.map(e => (e.name = array2.find(a => a.id == e.id)?.name || e.name, e));
console.log(newarray);

Edit according to @Roster's comment, if you want to override the whole entry use this line:

array1.map(e => (e = array2.find(a => a.id == e.id) || e, e));

Second example:

let array1 = [{
  'id': 1,
  'name': 'A'
}, {
  'id': 2,
  'name': 'B'
}, {
  'id': 3,
  'name': 'C'
}]

let array2 = [{
  'id': 1,
  'name': 'x'
}, {
  'id': 2,
  'name': 'y',
  'otherproperty': 42
}]

const newarray = array1.map(e => (e = array2.find(a => a.id == e.id) || e, e));
console.log(newarray);

Upvotes: 5

Related Questions