简体   繁体   English

从 JavaScript 中的对象数组中删除的有效方法

[英]Efficient way to delete from an array of objects in JavaScript

frontendtasks = [
                 {"id": 1, "name": "User Deletion", "script": "UserDeletion"},
                 {"id": 2, "name": "User Creation", "script_name": "UserCreation"}
                ]

backendtasks = [
                {"id": 1, "name": "User Deletion", "script": "UserDeletion_V2"}
               ]

I'm trying to delete the entry with id = 1 in frontendtask and push the entry from backendtask with this code.我正在尝试删除 frontendtask 中 id = 1 的条目,并使用此代码从 backendtask 中推送该条目。

if (backendtasks != 0) {
    for (updated_task in backendtasks ) {
        for (oldtask in frontendtasks) {
            if (frontendtasks[oldtask].id == backendtasks[updated_task].id) {
                frontendtasks[oldtask] = backendtasks[updated_task]
                delete backendtasks[updated_task];
                break;
            }
        }
    }
    for (new_task in backendtasks) {
        frontendtasks.unshift(backendtasks[new_task])
    }
}

This is really slow and CPU hits 100% in browser with 700 items.这真的很慢,CPU 在浏览器中达到 100%,有 700 个项目。 Is there any efficient way to implement this?有没有有效的方法来实现这个?

Don't loop through both arrays, instead use an object to map backend ids to values:不要遍历两个 arrays,而是使用 object 到 map 后端 ID 值:

const mappings = {};
for (const task of backendtasks) {
    mappings[task.id] = task;
}
for (let i = 0; i < frontendtasks.length; i ++) {
    const curid = frontendtasks[i].id;
    if (curid in mappings) {
        frontendtasks[i] = mappings[curid];
        delete mappings[curid];
    }
}
// push is faster than unshift
for (const key in mappings) {
    frontendtasks.push(mappings[key]);
}

Approach: Since you have 2 arrays, I would suggest first normalizing backend array to an object, and then iterate on frontend array and lookup in normalized object as lookup in object is O(1) as compared to O(n) in array.方法:由于您有 2 个 arrays,我建议首先将后端数组规范化为 object,然后迭代前端数组并在规范化的 object 中查找,因为与数组中的 O(n) 相比,object 中的查找为 O(1)。

 function getFrontendTasks(){ const frontendtasks = [ {"id": 1, "name": "User Deletion", "script": "UserDeletion"}, {"id": 2, "name": "User Creation", "script_name": "UserCreation"} ] const backendtasks = [ {"id": 1, "name": "User Deletion", "script": "UserDeletion_V2"} ] const normalizedBackendTasks = backendtasks.reduce((acc, val) => ({...acc, [val.id]: val}), {}); const newFrontendTasks = frontendtasks.map((task) => normalizedBackendTasks[task.id] || task); return newFrontendTasks } console.log(getFrontendTasks())

Creating a mapping table reduces the time complexity from O(n^2) to O(n) , by removing the nested for loops, which is very expensive.通过删除非常昂贵的嵌套for循环,创建映射表将时间复杂度从O(n^2)降低到O(n)

Try the following code:试试下面的代码:

const map = {};
backendtasks.forEach(bt => (map[bt.id] = bt));

frontendtasks.forEach((ft, idx) => {
  if (map[ft.id]) {
    frontendtasks[idx] = map[ft.id];
    delete map[ft.id];
  }
});

frontendtasks = frontendtasks.concat(Object.values(map));

Somehow I didn't see the map() function in any solution that creates a new array as shown below.不知何故,我在任何创建新数组的解决方案中都没有看到map() function,如下所示。

This will return the new array with the new value.这将返回具有新值的新数组。 As you can see, it takes an array, an id (this could be anything and any type tho), and a callback.如您所见,它需要一个数组、一个 id(这可以是任何东西和任何类型)和一个回调。

Searcing for the id in the array and runs the callback when found.在数组中搜索id并在找到时运行回调。 Efficient way for what you want to do.您想做的事情的有效方法。

In the callback, I used find() on the backendtasks simply because I need to find the item which has the same id (id: 1).在回调中,我在backendtasks上使用find()只是因为我需要找到具有相同id (id: 1) 的项目。

When found, it returns the item from backendtasks then completes the function by returning that value in the map() function.找到后,它从backendtasks返回该项目,然后通过在map() function 中返回该值来完成 function。

So, this should be O(n) , considering that the callback only runs once and it's a more elegant solution for multiple uses in my opinion.所以,这应该是O(n) ,考虑到回调只运行一次,在我看来它是一个更优雅的多次使用解决方案。

const frontendtasks: any[] = [];
const backendtasks: any[] = [];

const fn = (arr: any[], id: number, callback: (removed: any) => any) => {
  return arr.map((ft) => {
    if (ft.id !== id) return ft;
    else return callback(ft);
  });
};

fn(frontendtasks, 1, (rm) => backendtasks.find((id) => rm.id === id));
frontendtasks = [
                 {"id": 1, "name": "User Deletion", "script": "UserDeletion"},
                 {"id": 2, "name": "User Creation", "script_name": "UserCreation"}
                ]

backendtasks = [
                {"id": 1, "name": "User Deletion", "script": "UserDeletion_V2"}
               ]

I'm trying to delete the entry with id = 1 in frontendtask and push the entry from backendtask with this code.我正在尝试删除 frontendtask 中 id = 1 的条目,并使用此代码从 backendtask 推送条目。

if (backendtasks != 0) {
    for (updated_task in backendtasks ) {
        for (oldtask in frontendtasks) {
            if (frontendtasks[oldtask].id == backendtasks[updated_task].id) {
                frontendtasks[oldtask] = backendtasks[updated_task]
                delete backendtasks[updated_task];
                break;
            }
        }
    }
    for (new_task in backendtasks) {
        frontendtasks.unshift(backendtasks[new_task])
    }
}

This is really slow and CPU hits 100% in browser with 700 items.这真的很慢,在浏览器中 CPU 达到 100%,有 700 个项目。 Is there any efficient way to implement this?有没有有效的方法来实现这一点?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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