按对象属性从数组中删除对象

IT技术 javascript
2021-01-25 15:54:04
var listToDelete = ['abc', 'efg'];

var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

如何通过匹配对象属性从数组中删除对象?

请只使用原生 JavaScript。

我在使用 splice 时遇到问题,因为每次删除时长度都会减少。在原始索引上使用克隆和拼接仍然会给您带来长度减少的问题。

6个回答

我假设你用过splice这样的东西?

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
    }
}

修复错误所需要做的就是i在下一次递减,然后(向后循环也是一种选择):

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
        i--;
    }
}

为了避免线性时间删除,您可以编写要保留在数组上的数组元素

var end = 0;

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) === -1) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

为了避免现代运行时中的线性时间查找,您可以使用哈希集:

const setToDelete = new Set(listToDelete);
let end = 0;

for (let i = 0; i < arrayOfObjects.length; i++) {
    const obj = arrayOfObjects[i];

    if (setToDelete.has(obj.id)) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

它可以包含在一个很好的函数中:

const filterInPlace = (array, predicate) => {
    let end = 0;

    for (let i = 0; i < array.length; i++) {
        const obj = array[i];

        if (predicate(obj)) {
            array[end++] = obj;
        }
    }

    array.length = end;
};

const toDelete = new Set(['abc', 'efg']);

const arrayOfObjects = [{id: 'abc', name: 'oh'},
                        {id: 'efg', name: 'em'},
                        {id: 'hij', name: 'ge'}];

filterInPlace(arrayOfObjects, obj => !toDelete.has(obj.id));
console.log(arrayOfObjects);

如果你不需要就地做,那就是Array#filter

const toDelete = new Set(['abc', 'efg']);
const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));

您可以通过其属性之一删除项目,而无需使用任何 3rd 方库,如下所示:

var removeIndex = array.map(item => item.id).indexOf("abc");

~removeIndex && array.splice(removeIndex, 1);
这个答案比所选的解决方案更快、更优雅:jsben.ch/ld9op
2021-03-17 15:54:04
(另外,您可以跳过少数元素的集合构造,然后它再次更快,即使您缓存了 id 数组。此外,这两种方法不会以相同的方式处理重复项。不确定这是否重要。)
2021-03-19 15:54:04
或者,如果您对最后一行的波浪号感到困惑,您可能会发现这更清楚: (removeIndex >= 0) && array.splice(removeIndex, 1);
2021-03-25 15:54:04
@ZackLee:当然,对于 5/10 元素,它可能会更快。这是 50/100:jsben.ch/55g97
2021-04-08 15:54:04

使用 lodash/下划线:

如果要修改现有数组本身,则必须使用splice这是使用下划线/lodash 的findWhere更好/可读的方法

var items= [{id:'abc',name:'oh'}, // delete me
                  {id:'efg',name:'em'},
                  {id:'hij',name:'ge'}];

items.splice(_.indexOf(items, _.findWhere(items, { id : "abc"})), 1);

使用 ES5 或更高版本

没有lodash/下划线

从 ES5 开始,我们findIndex在数组上方法,所以没有 lodash/underscore 更容易

items.splice(items.findIndex(function(i){
    return i.id === "abc";
}), 1);

(几乎所有现代浏览器都支持 ES5)

关于 findIndex及其浏览器兼容性

好东西。我会将此添加到我的工具带
2021-03-11 15:54:04
如何删除对象数组中的所有项目,但我也需要回调
2021-03-18 15:54:04
喜欢这个 ES5 建议,因为它甚至可以用更短的方式编写 items.splice(items.findIndex(i => i.id === "abc"), 1)
2021-03-21 15:54:04
回调是什么意思,你可以使用上面的代码从数组中删除对象..
2021-03-31 15:54:04
请小心。这不会删除数组中具有相同“id”的所有对象。
2021-04-09 15:54:04

findIndex 适用于现代浏览器:

var myArr = [{id:'a'},{id:'myid'},{id:'c'}];
var index = myArr.findIndex(function(o){
  return o.id === 'myid';
})
if (index !== -1) myArr.splice(index, 1);
与其他人相比,非常简单的答案并且效果很好。
2021-03-11 15:54:04
简单而强大的回答
2021-03-30 15:54:04
我喜欢这个现代答案,除了当 index=-1 时你的代码没有捕捉到这种情况
2021-04-02 15:54:04

根据给定数组中的 id 删除对象;

const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);
filter() 即使在找到第一个元素后也会继续过滤。
2021-04-02 15:54:04