Find and replace object in array (based on id)

14,157

Solution 1

Use Array.map and Array.find():

const allItems = [
  { 'id': 1, 'category_id': 1, 'text': 'old' },
  { 'id': 2, 'category_id': 1, 'text': 'old' }
];

const newItems = [
  { 'id': 1, 'category_id': 1, 'text': 'new', 'more_info': 'abcd' },
  { 'id': 2, 'category_id': 1, 'text': 'new', 'more_info': 'abcd' }
];

const result = allItems.map(x => {
  const item = newItems.find(({ id }) => id === x.id);
  return item ? item : x;
});

console.log(result);

This can even be shortened by using a logical or to return the original item when the call to find returns undefined:

const result = allItems.map(x => newItems.find(({ id }) => id === x.id) || x);

Regarding your code, you can't use indexOf since it only compares primitive values or references in the case of arrays and objects.

Solution 2

Depending on how large your input arrays are, you might consider adding an intermediate step to build a "map" of your newItems, where the key of this map is the id of the item.

Using a mapping such as this would allow for much faster reconciliation (and replacement) of items from the allItems array with items in the newItems array:

function replaceItemsOnId(items, replacement) {

  /* 
  Create a map where the key is the id of replacement items.
  This map will speed up the reconciling process in the 
  subsequent "map" stage
  */
  const replacementMap = replacement.reduce((map, item) => {

    map[ item.id ] = item
    return map;

  }, {})

  /*
  Map the items to a new array where items in the result array
  are either clones of the orignals, or replaced by items of 
  "replacement" array where thier id matches the item being mapped 
  */
  return items.map(item => {

    const use = replacementMap[ item.id ] || item

    return { ...use }

  })
}

const allItems = [
  {
    'id': 1,
    'category_id': 1,
    'text': 'old',
  },
  {
    'id': 2,
    'category_id': 1,
    'text': 'old'
  }
]

const newItems = [
  {
    'id': 1,
    'category_id': 1,
    'text': 'new',
    'more_info': 'abcd'
  },
  {
    'id': 2,
    'category_id': 1,
    'text': 'new',
    'more_info': 'abcd'
  }
]


console.log(replaceItemsOnId(allItems, newItems))

Solution 3

Just use map like so:

const allItems = [{
    'id': 1,
    'category_id': 1,
    'text': 'old',
  },
  {
    'id': 2,
    'category_id': 1,
    'text': 'old'
  }
];
const newItems = [{
    'id': 1,
    'category_id': 1,
    'text': 'new',
    'more_info': 'abcd'
  },
  {
    'id': 2,
    'category_id': 1,
    'text': 'new',
    'more_info': 'abcd'
  }
];

const replacedItems = allItems.map(e => {
  if (newItems.some(({ id }) => id == e.id)) {
    return newItems.find(({ id }) => id == e.id);
  }
  return e;
});

console.log(replacedItems);

Solution 4

Just using a simple Array.map and a method to check the other array.

const allItems = [
  {
    'id': 1,
    'category_id': 1,
    'text': 'old',
  },
  {
    'id': 2,
    'category_id': 1,
    'text': 'old'
  },
  {
    'id': 3,
    'category_id': 1,
    'text': 'old_same'
  }
  
]

const newItems = [
  {
    'id': 1,
    'category_id': 1,
    'text': 'new',
    'more_info': 'abcd'
  },
  {
    'id': 2,
    'category_id': 1,
    'text': 'new',
    'more_info': 'abcd'
  }
]

const findNewItem = (oldItem) => newItems.find(item => item.id === oldItem.id);

let arr = allItems.map(item => findNewItem(item)||item);

console.log(arr);
Share:
14,157

Related videos on Youtube

jj008
Author by

jj008

Updated on September 15, 2022

Comments

  • jj008
    jj008 over 1 year

    Got a bit of a puzzle here...I want to loop through allItems and return allItems but replace with any newItems that matches its id. How can I look for a match on id and then replace it with the correct object into the array?

    const allItems = [
      {
        'id': 1,
        'category_id': 1,
        'text': 'old',
      },
      {
        'id': 2,
        'category_id': 1,
        'text': 'old'
      }
    ]
    
    const newItems = [
      {
        'id': 1,
        'category_id': 1,
        'text': 'new',
        'more_info': 'abcd'
      },
      {
        'id': 2,
        'category_id': 1,
        'text': 'new',
        'more_info': 'abcd'
      }
    ]
    

    What I tried so far:

    for(let i = 0; i < allItems.length; i++) {
      if(newItems.indexOf(allItems[i].id) > -1){
        allItems[i] = newItems
      }
    }
    

    How can I get the position of the object in newItems and then replace it into allItems?