Удалять объекты из массива по свойству объекта
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.
У меня возникли проблемы с использованием сплайсинга, потому что с каждым удалением уменьшается длина.
Использование клона и сплайсинга по индексу orignal все еще оставляет вам проблему уменьшения длины.
Ответы
Ответ 1
Я полагаю, вы использовали 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);
Ответ 2
Вы можете удалить элемент по одному из своих свойств, не используя любые сторонние библиотеки, такие как:
var removeIndex = array.map(function(item) { return item.id; })
.indexOf("abc");
~removeIndex && array.splice(removeIndex, 1);
Ответ 3
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);
Ответ 4
С lodash/подчеркиванием:
Если вы хотите изменить сам существующий массив, тогда мы должны использовать соединение. Вот немного лучше/читабельный способ с использованием findWhere подчеркивания /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);
С ES5 или выше
(без подчеркивания/подчеркивания)
С ES5 и далее у нас findIndex
метод findIndex
для массива, так что его легко без lodash/underscore
items.splice(items.findIndex(function(i){
return i.id === "abc";
}), 1);
(ES5 поддерживается почти во всех современных браузерах)
О findIndex и его совместимости с браузерами
Ответ 5
Если вы просто хотите удалить его из существующего массива и не создать новый, попробуйте:
var items = [{Id: 1},{Id: 2},{Id: 3}];
items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);
Ответ 6
Только родной 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' } ]
Согласно определению "Array.prototype.reduceRight" в ECMA-262:
reduRight напрямую не мутирует объект, для которого он вызывается, но объект может быть мутирован вызовами callbackfn.
Так что это правильное использование reduceRight
.
Ответ 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;
});
Ответ 8
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);
}
}
Ответ 9
Проверьте это с помощью Set и ES6 filter.
let result = arrayOfObjects.filter( el => (-1 == listToDelete.indexOf(el.id)) );
console.log(result);
Вот JsFiddle: https://jsfiddle.net/jsq0a0p1/1/
Ответ 10
с фильтром и 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));
Ответ 11
Если вам нравятся короткие и самоописательные параметры или если вы не хотите использовать 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)
Ответ 12
Удалить объект по его идентификатору в заданном массиве;
const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);