简体   繁体   中英

Update Multiple Objects in Nested Arrays

I have an array of multi dimensional objects:

var arr = [
  {
    id: '10c',
    name: 'item 1'
    children: [
      {id: '11v', name: 'Item 1 child 1'},
      {id: '12c', name: 'Item 1 child 2'}
    ]
  },
  {
    id: '13v',
    name: 'item 2'
    children: [
      {id: '26e', name: 'Item 2 child 1'},
      {id: '7a', name: 'Item 2 child 2'}
    ]
  }
]

and another object of data:

var array = [
  {id: '12c', name: 'New name 1'},
  {id: '26e', name: 'New name 2'},
  {id: '11v', name: 'New name 3'},
];

If I want to update the name value of the respective objects in arr , based on the id value in array , how would be the best way of doing that?

arr might be more than 2 levels deep, so I would like to be able to do it without having to nest multiple forEach

Try this:

function update(items, id, name) {
    var item;
    for (var i = 0; i < items.length; i++) {
        item = items[i];
        if (item.id === id) {
            item.name = name;
            return;
        }
        if (item.children) {
             update(item.children, id, name);
        }
    }
}

Then:

update(arr, '11v', 'test');

Updating by array :

array.forEach(function (item) {
    update(arr, item.id, item.name);
});

Use a recursive solution and make use of the inherent mutability of Javascript.

First build up a flat map representation of all the objects.

function createObjectMap(array) {
  var map = {};

  array.forEach(function(obj) {
    map[obj.id] = obj;

    if(obj.children) {
      Object.assign(map, createObjectMap(obj.children));
    }
  });

  return map;
}

Now you've got a map of id -> object you can use. They reference the same mutable objects, so you can mutate them in place and know that they'll also update in the original data structure.

function update(map, updates) {
  updates.forEach(function(update) {
    map[update.id].name = update.name;
  });
}

This conversion to O(1) lookup time means you don't have to write any searching logic.

You could use angular $filter to do the same

//to get element
function getFiltered(collection, obj){
   var filtered = $filter('filter')(collection, obj, true);
   if(filtered[0])
     return filtered[0]
   if(collection.children)
     return getFiltered(collection.children, obj, true);
}

angular.forEach(array, function(element){
    var filtered = getFiltered(array, { id: element.id })
    if(filtered[0]) filtered.name = element.name;
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM