usuń obiekty z tablicy według właściwości obiektu

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

Jak usunąć obiekt z tablicy, dopasowując właściwość obiektu?

Tylko natywny JavaScript.

Mam problemy z używaniem połączenia, ponieważ długość zmniejsza się przy każdym usunięciu. Korzystanie z funkcji klonowania i łączenia na indeksie oryginalnym nadal pozostawia problem z malejącą długością.

Dan Kanze
źródło
1
Zapętlenie wstecz powinno rozwiązać problem ze zmianą długości
Ian
1
Szkoda, że ​​nie ma standardowego prawidłowego sposobu usuwania elementów z tablicy obiektów. Nic dziwnego, że istnieje tak wiele skryptów innych firm. To podstawowa sprawa.
gitara
Możliwy duplikat elementu Usuń tablicę na podstawie właściwości obiektu
vahdet

Odpowiedzi:

155

Zakładam, że użyłeś spliceczegoś takiego?

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

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

Wszystko, co musisz zrobić, aby naprawić błąd, to zmniejszyć iwartość następnym razem (a pętla do tyłu jest również opcją):

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

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

Aby uniknąć usuwania w czasie liniowym, możesz napisać elementy tablicy, które chcesz zachować w tablicy:

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;

i aby uniknąć wyszukiwania w czasie liniowym w nowoczesnym środowisku uruchomieniowym, możesz użyć zestawu skrótów:

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;

który można opakować w fajną funkcję:

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

Jeśli nie musisz tego robić na miejscu, to Array#filter:

const toDelete = new Set(['abc', 'efg']);
const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));
Ry-
źródło
79

Możesz usunąć element według jednej z jego właściwości bez korzystania z bibliotek innych firm, takich jak ta:

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

~removeIndex && array.splice(removeIndex, 1);
parlament
źródło
1
To naprawdę elegancka odpowiedź.
Scott Silvi
Kolejna rzecz, której chcę, będą oddzielne przyciski dla każdego obiektu w tablicy. jeśli chcę usunąć ten konkretny obiekt w klikniętym przycisku tablicy i powinien zostać przeniesiony do innej dodatkowej tablicy. jak to zrobić . Użyłem kątowego js ng-repeat do generowania elementów. czy możesz mi pomóc
Thilak Raj
bardzo ładne i eleganckie podejście. sława! Tylko jedna rzecz do ostrożności; jeśli wymagany indeks nie zostanie znaleziony w tablicy map, zwróci -1; w ten sposób połączenie usunie ostatni element.
mcy
15
Lub jeśli zdezorientujesz się tyldą w ostatnim wierszu, możesz uznać to za bardziej przejrzyste: (removeIndex> = 0) && array.splice (removeIndex, 1);
wojjas
1
@parliament - czy w Twoim przykładzie jest jakaś dokumentacja dotycząca tyldy? Nigdy wcześniej tego nie widziałem.
webdad3
43

Z lodash / podkreśleniem:

Jeśli chcesz zmodyfikować samą istniejącą tablicę, musimy użyć splice . Oto trochę lepszy / czytelny sposób użycia funkcji findWhere podkreślenia / 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);

Z ES5 lub nowszym

( bez lodash / podkreślenia )

Od wersji ES5 mamy findIndexmetodę array, więc jest to łatwe bez lodash / underscore

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

(ES5 jest obsługiwany w prawie wszystkich przeglądarkach Morden)

Informacje o findIndex i jego zgodności z przeglądarkami

Rahul R.
źródło
jak usunąć wszystkie elementy z tablicy obiektów, ale potrzebuję również wywołania zwrotnego
Muhaimin
co masz na myśli przez callback, możesz użyć powyższego kodu, aby usunąć obiekt z tablicy ..
Rahul R.
1
Niezłe.
Dodam
Kolejna rzecz, której chcę, będą oddzielne przyciski dla każdego obiektu w tablicy. jeśli chcę usunąć ten konkretny obiekt w klikniętym przycisku tablicy i powinien zostać przeniesiony do innej dodatkowej tablicy. jak to zrobić . Użyłem kątowego js ng-repeat do generowania elementów. czy możesz mi pomóc
Thilak Raj
1
Uwielbiam tę sugestię ES5, ponieważ można ją nawet napisać w krótszy sposóbitems.splice(items.findIndex(i => i.id === "abc"), 1)
bramchi
27

findIndex działa w nowoczesnych przeglądarkach:

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);
fatlinesofcode
źródło
Podoba mi się ta nowoczesna odpowiedź, z wyjątkiem tego, że twój kod nie łapie przypadku, gdy index = -1
rmcsharry
2
bardzo prosta odpowiedź w porównaniu z innymi i działa dobrze.
Arun
prosty, ale potężny asnwer
Shelly
15

Aby usunąć obiekt według jego identyfikatora w podanej tablicy;

const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);
Naresh Chennuri
źródło
10

Jeśli chcesz po prostu usunąć ją z istniejącej tablicy i nie tworzyć nowej, spróbuj:

var items = [{Id: 1},{Id: 2},{Id: 3}];
items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);
user2704940
źródło
7
zauważ, że ta odpowiedź wymaga biblioteki podkreślenia
JoshuaDavid
2
Nie polecam tego, ponieważ jeśli element nie zostanie znaleziony _.indexOf zwróci -1 => items.splice (-1,1)
user1441287
6

Zapętlaj w odwrotnej kolejności, zmniejszając wartość, iaby uniknąć problemu:

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

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

Lub użyj filter:

var newArray = arrayOfObjects.filter(function(obj) {
    return listToDelete.indexOf(obj.id) === -1;
});
Felix Rabe
źródło
5

Sprawdź to za pomocą zestawu i filtra ES6.

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

Oto JsFiddle: https://jsfiddle.net/jsq0a0p1/1/

Miroslav Savovski
źródło
1
Działa świetnie!
Antoni Kępinski
Moim zdaniem najbardziej nowoczesne i eleganckie podejście.
AC Patrice
4

Tylko natywny JavaScript.

Jako alternatywne, bardziej "funkcjonalne" rozwiązanie, pracując na ECMAScript 5, możesz użyć:

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' } ]

Zgodnie z definicją „Array.prototype.reduceRight” w ECMA-262 :

RedukcjaRight nie zmienia bezpośrednio obiektu, na którym jest wywoływana, ale obiekt może zostać zmutowany przez wywołania funkcji callbackfn .

Więc to jest ważne użycie reduceRight.

Sylvain Leroux
źródło
2
var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

jak na twoją odpowiedź będzie tak. po kliknięciu określonego obiektu wyślij indeks w parametrze funkcji delete me. Ten prosty kod będzie działał jak urok.

function deleteme(i){
    if (i > -1) {
      arrayOfObjects.splice(i, 1);
    }
}
Subhojit Mondal
źródło
1
Dzięki temu bardzo pomogło :)
RAJESH KUMAR ARUMUGAM
1

z filtrem & indexOf

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

z filtrem i zawiera

withLodash = _.filter(arrayOfObjects, (obj) => (!listToDelete.includes(obj.id)))
withoutLodash = arrayOfObjects.filter(obj => !listToDelete.includes(obj.id));
user3437231
źródło
0

Jeśli lubisz krótkie i samoopisujące się parametry lub jeśli nie chcesz używać spliceprostego filtru do przodu lub jeśli jesteś po prostu osobą taką jak ja 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});
}

I przykładowe użycie:

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)
Mehmet Kaplan
źródło
-1

Możesz użyć filter. Ta metoda zawsze zwraca element, jeśli warunek jest prawdziwy. Więc jeśli chcesz usunąć przez id, musisz zachować wszystkie elementy, które nie pasują do podanego id. Oto przykład:

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

David Benitez Riba
źródło