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

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

4

13 回答 13

175

我假设你用过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));
于 2013-05-10T22:39:48.900 回答
115

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

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

~removeIndex && array.splice(removeIndex, 1);
于 2014-10-12T16:22:06.433 回答
73

With lodash/underscore:

If you want to modify the existing array itself, then we have to use splice. Here is the little better/readable way using findWhere of underscore/lodash:

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);

With ES5 or higher

(without lodash/underscore)

With ES5 onwards we have findIndex method on array, so its easier without lodash/underscore

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

(ES5 is supported in almost all morden browsers)

About findIndex, and its Browser compatibility

于 2014-03-12T16:01:30.683 回答
34

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);
于 2016-08-25T05:16:16.857 回答
31

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

const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);
于 2019-04-12T09:12:50.957 回答
10

如果您只想从现有数组中删除它而不创建新数组,请尝试:

var items = [{Id: 1},{Id: 2},{Id: 3}];
items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);
于 2013-08-21T19:32:42.933 回答
9

使用 Set 和 ES5 过滤器检查这一点。

  let result = arrayOfObjects.filter( el => (-1 == listToDelete.indexOf(el.id)) );
  console.log(result);

这是 JsFiddle: https ://jsfiddle.net/jsq0a0p1/1/

于 2018-05-23T09:04:02.500 回答
7

通过递减反向循环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;
});
于 2014-06-11T23:11:07.277 回答
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.

于 2016-01-07T21:21:09.340 回答
2
var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

根据你的回答会是这样的。当您单击某个特定对象时,请发送参数中的索引以用于删除我功能。这个简单的代码将像魅力一样工作。

function deleteme(i){
    if (i > -1) {
      arrayOfObjects.splice(i, 1);
    }
}
于 2017-11-25T08:03:19.963 回答
0

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

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

于 2020-04-02T21:07:37.077 回答
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)
于 2017-06-20T16:36:20.163 回答
0

带过滤器和 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));
于 2018-08-24T15:47:26.657 回答