通过对象属性从数组中删除对象


137
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。

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


1
向后循环应解决长度变化的问题
Ian

1
很遗憾,没有一种标准的正确方法可以从对象数组中删除项目。难怪有这么多的第三方脚本。这是基本的事情。
guitarlass

Answers:


155

我以为你用过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));

79

您可以通过其属性之一删除某项,而无需使用任何第三方库,例如:

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

~removeIndex && array.splice(removeIndex, 1);

1
这是一个非常优雅的答案。
斯科特·席尔维

我想要的另一件事,是数组中的每个对象都有单独的按钮。如果我想删除单击的数组按钮中的特定对象,那应该移到另一个辅助数组。怎么做 。我已经使用angular js ng-repeat生成项目。您能帮我吗
Thilak Raj

非常好的和优雅的方法。赞!请注意,只有一件事;如果在地图数组上找不到所需的索引,它将返回-1;因此,拼接将删除最后一个元素。
mcy

15
或者,如果您对最后一行的波浪线感到困惑,则可能会更清楚:(removeIndex> = 0)&& array.splice(removeIndex,1);
wojjas

1
@parliament-您的示例中的波浪号上有任何文档吗?我以前从未见过。
webdad3 18/09/14

43

使用lodash /下划线:

如果要修改现有数组本身,则必须使用splice。这是使用underscore / 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或更高版本

不带下划线/下划线

从ES5开始,我们findIndex在数组上有了方法,因此无需lodash / underscore即可轻松实现

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

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

关于findIndex及其浏览器兼容性


我如何删除对象数组中的所有项目,但我也需要回调
Muhaimin 2014年

你是什么意思的回调,以及,你可以使用上面的代码从数组删除对象..
拉胡尔河

1
好一个。我将其添加到工具栏中
abyrne85

我想要的另一件事,是数组中的每个对象都有单独的按钮。如果我想删除单击的数组按钮中的特定对象,那应该移到另一个辅助数组。怎么做 。我已经使用angular js ng-repeat生成项目。您能帮我吗
Thilak Raj

1
喜欢这个ES5的建议,因为它甚至可以用更短的方式编写items.splice(items.findIndex(i => i.id === "abc"), 1)
Bramchi

27

findIndex适用于现代浏览器:

var myArr = [{id:'a'},{id:'myid'},{id:'c'}];
var index = arr.findIndex(function(o){
     return o.id === 'myid';
})
if (index !== -1) myArr.splice(index, 1);

我喜欢这个现代的答案,除了您的代码在index = -1时
不起作用

2
与其他人相比,答案很简单,效果很好。
阿伦

简单而强大的解决方案
Shelly

15

通过给定数组中的ID删除对象;

const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);

10

如果您只想从现有阵列中删除它而不创建一个新阵列,请尝试:

var items = [{Id: 1},{Id: 2},{Id: 3}];
items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);

7
请注意,此答案需要下划线
JoshuaDavid

2
我不建议这样做,因为如果未找到_.indexOf,将返回-1 => items.splice(-1,1)
user1441287'1

6

通过递减i来反向循环,避免出现此问题:

for (var i = arrayOfObjects.length - 1; i >= 0; i--) {
    var obj = arrayOfObjects[i];

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

或使用filter

var newArray = arrayOfObjects.filter(function(obj) {
    return listToDelete.indexOf(obj.id) === -1;
});


4

请只使用本机JavaScript。

作为在ECMAScript 5上工作的替代的,更具“功能性”的解决方案,您可以使用:

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

arrayOfObjects.reduceRight(function(acc, obj, idx) {
    if (listToDelete.indexOf(obj.id) > -1)
        arrayOfObjects.splice(idx,1);
}, 0); // initial value set to avoid issues with the first item and
       // when the array is empty.

console.log(arrayOfObjects);
[ { id: 'hij', name: 'ge' } ]

根据ECMA-262中'Array.prototype.reduceRight'的定义

reduceRight不会直接改变在其上调用它的对象,但是可以通过对callbackfn的调用来改变该对象。

因此,这是的有效用法reduceRight


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

根据您的答案将是这样。当您单击某个特定对象时,将参数中的索引发送给Delete me功能。这个简单的代码将像魅力一样工作。

function deleteme(i){
    if (i > -1) {
      arrayOfObjects.splice(i, 1);
    }
}

1
认为这对很多人有帮助:)
RAJESH KUMAR ARUMUGAM '18

1

与filter&indexOf

withLodash = _.filter(arrayOfObjects, (obj) => (listToDelete.indexOf(obj.id) === -1));
withoutLodash = arrayOfObjects.filter(obj => listToDelete.indexOf(obj.id) === -1);

带过滤器和包含

withLodash = _.filter(arrayOfObjects, (obj) => (!listToDelete.includes(obj.id)))
withoutLodash = arrayOfObjects.filter(obj => !listToDelete.includes(obj.id));

0

如果您喜欢简短的自我描述参数,或者您不想使用splice直接筛选器,或者您只是像我这样的SQL人员:

function removeFromArrayOfHash(p_array_of_hash, p_key, p_value_to_remove){
    return p_array_of_hash.filter((l_cur_row) => {return l_cur_row[p_key] != p_value_to_remove});
}

以及示例用法:

l_test_arr = 
[
    {
         post_id: 1,
        post_content: "Hey I am the first hash with id 1"
    },
    {
        post_id: 2,
        post_content: "This is item 2"
    },
    {
        post_id: 1,
        post_content: "And I am the second hash with id 1"
    },
    {
        post_id: 3,
        post_content: "This is item 3"
    },
 ];



 l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 2); // gives both of the post_id 1 hashes and the post_id 3
 l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 1); // gives only post_id 3 (since 1 was removed in previous line)

-1

您可以使用filter。如果条件为true,则此方法始终返回元素。因此,如果要按ID删除,则必须保留所有与给定ID不匹配的元素。这是一个例子:

arrayOfObjects = arrayOfObjects.filter(obj => obj.id!= idToRemove)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.