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

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。

我有麻烦使用剪接,因为长度减少每删除。 使用克隆和剪接的原始指数仍然留给你的问题,长度减少。

362158 次浏览

我猜你用的是 splice之类的吧?

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


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

要修复这个 bug,只需要在下次修复时减少 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));

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

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

用 loash/下划线:

如果您想要修改现有的数组本身,那么我们必须使用 拼接。下面是使用下划线/loash 的 找到在哪里的一点更好/可读的方法:

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方法,所以不使用 loash/underscore 更容易

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

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

关于 findIndex 及其浏览器兼容性

通过递减 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;
});

您可以通过其中一个属性删除一个项目,而不需要使用任何第三方库,如下所示:

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


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

请只使用本地 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的有效用法。

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

如果你喜欢简短和自我描述的参数,或者如果你不想使用 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)
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);
}
}

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

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

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

具有过滤器和索引

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

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

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

你可以使用 filter。如果条件为 true,则此方法始终返回元素。因此,如果你想通过 id 移除,你必须保留所有与给定 id 不匹配的元素。这里有一个例子:

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

一个非常简短的方法是:

for (i = 0; i < listToDelete.length; i++) {
arrayOfObjects = arrayOfObjects.filter((e) => e.id !== listToDelete[i])
}

错误的方式

首先,建议使用 filter的任何答案实际上都不会删除该项。这里有一个快速测试:

var numbers = [1, 2, 2, 3];
numbers.filter(x => x === 2);
console.log(numbers.length);

在上面的代码中,numbers数组将保持完整(不会删除任何内容)。filter方法返回一个新数组,其中包含满足条件 x === 2的所有元素,但原始数组保持不变。

当然,你可以这样做:

var numbers = [1, 2, 2, 3];
numbers = numbers.filter(x => x === 2);
console.log(numbers.length);

但这只是将一个新数组赋给 numbers


从数组中删除项的正确方法

正确的方法之一,有多于1种,就是按照下面的方法来做。请记住,这里的例子故意有重复的项目,以便删除重复可以考虑。

var numbers = [1, 2, 2, 3];


// Find all items you wish to remove
// If array has objects, then change condition to x.someProperty === someValue
var numbersToRemove = numbers.filter(x => x === 2);


// Now remove them
numbersToRemove.forEach(x => numbers.splice(numbers.findIndex(n => n === x), 1));


// Now check (this is obviously just to test)
console.log(numbers.length);
console.log(numbers);

现在您将注意到 length返回2,表示数组中只剩下数字1和3。


对你来说

具体回答你的问题是这样的:

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

答案是:

listToDelete.forEach(x => arrayOfObjects.splice(arrayOfObjects.findIndex(n => n.id === x), 1));

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


var result = arrayOfObjects.filter(object => !listToDelete.some(toDelete => toDelete === object.id));


console.log(result);