jj008
jj008

Reputation: 1093

Find and replace within nested array

I have 2 arrays that are structured differently, I want to check allItems and replace anything that exists in newItems. I have try using map but I'm not sure how to deal with nested arrays of objects.

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

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

I want to return:

  {
    'id': 1,
    'text': 'new',
    'more_info': 'abcd',
    'child': [
      {
        'id': 2,
        'text': 'new'
        'more_info': 'abcd'
      }
    ]
  }
]

My code (this doesn't deal with the child level):

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

Upvotes: 0

Views: 172

Answers (2)

GregL
GregL

Reputation: 38131

The following will give you some hints on how to approach this problem, without providing the final answer.

Two Approaches

There are two approaches you can take to solve this problem:

  1. Implement a findItemById(id) method that recursively traverses through allItems to find an item with a specific id. Then you can call that function for each entry in newItems and override the relevant properties if you find it.

  2. Implement a traverseItems(itemTree, callback) method that recursively traverses each level of the item tree, and then calls callback with each item and child item it comes across. The callback would then check if that item's ID matches one in newItems and if so, overwrites it's properties with those from the entry in newItems.

Commonalities

If you think about these two approaches, it becomes obvious that the thing needed in both approaches is a recursive traversal function that can go down through all the levels of allItems. So focus on getting that basic algorithm right, and then you can decide between the two. (Hint: one of them is likely to be more efficient than the other, but for small data sets, it really won't matter).

Upvotes: 1

Ele
Ele

Reputation: 33726

child property represents only one, but this alternative loops the whole array.

You can use recursion to go deeper and updated the found objects by id.

This approach mutates the original array

const allItems = [{  'id': 1,  'text': 'old',  'child': [    {      'id': 2,      'text': 'old'    }  ]}],
      newItems = [  {    'id': 1,    'text': 'new',    'more_info': 'abcd'  },  {    'id': 2,    'text': 'new',    'more_info': 'abcd'  }]
      looper = (arr, items) => {
        arr.forEach(outer => {
          let found = items.find(n => outer.id === n.id);
          if (found) {
            Object.assign(outer, found);
            if (outer.child) looper(outer.child, items);
          }
        });
      };

looper(allItems, newItems);
console.log(allItems);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions