rimuove gli oggetti dall'array per proprietà dell'oggetto


138
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

Come rimuovo un oggetto dall'array abbinando la proprietà dell'oggetto?

Solo JavaScript nativo per favore.

Sto riscontrando problemi nell'utilizzo della giunzione perché la lunghezza diminuisce ad ogni eliminazione. L'uso del clone e la giunzione sull'indice originale ti lasciano ancora il problema della lunghezza decrescente.


1
Il looping all'indietro dovrebbe risolvere il problema di modifica della lunghezza
Ian

1
È un peccato che non ci sia un modo corretto standard per rimuovere elementi da un array di oggetti. Non c'è da stupirsi che ci siano così tanti script di terze parti. È una cosa basilare.
Guitarlass

Risposte:


155

Presumo tu abbia usato splicequalcosa del genere?

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

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

Tutto quello che devi fare per correggere il bug è il decremento iper la prossima volta, quindi (e anche il looping all'indietro è un'opzione):

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

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

Per evitare eliminazioni di tempi lineari, è possibile scrivere elementi dell'array che si desidera conservare sull'array:

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;

e per evitare ricerche nel tempo lineare in un runtime moderno, è possibile utilizzare un set di hash:

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;

che può essere racchiuso in una bella funzione:

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

Se non hai bisogno di farlo sul posto, questo è Array#filter:

const toDelete = new Set(['abc', 'efg']);
const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));

79

Puoi rimuovere un oggetto da una delle sue proprietà senza usare librerie di terze parti come questa:

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

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

1
Questa è una risposta davvero elegante.
Scott Silvi,

un'altra cosa che voglio, ci saranno pulsanti separati per ogni oggetto nella matrice. se voglio cancellare quel particolare oggetto nel pulsante dell'array cliccato e che dovrebbe essere spostato su un altro array secondario. come farlo . ho usato angular js ng-repeat per generare oggetti. mi potete aiutare
Thilak Raj,

approccio molto bello ed elegante. complimenti! Solo una cosa per cautela; se l'indice richiesto non viene trovato sull'array di mappe, restituirà -1; quindi la giunzione rimuoverà l'ultimo elemento.
mcy

15
O se vieni confuso dalla tilde sull'ultima riga, potresti trovare questo più chiaro: (removeIndex> = 0) && array.splice (removeIndex, 1);
Wojjas,

1
@parparlamento - c'è qualche documentazione sulla tilde nel tuo esempio? Non l'ho mai visto prima.
webdad3,

43

Con lodash / underscore:

Se vuoi modificare l'array esistente stesso, allora dobbiamo usare splice . Ecco il modo migliore / leggibile usando findWhere di 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);

Con ES5 o versione successiva

( senza lodash / carattere di sottolineatura )

Con ES5 in poi abbiamo il findIndexmetodo su array, quindi è facile senza lodash / underscore

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

(ES5 è supportato in quasi tutti i browser morden)

Informazioni su findIndex e la sua compatibilità con il browser


come rimuovo tutti gli elementi nella matrice di oggetti ma ho bisogno anche del callback
Muhaimin

cosa intendi per callback? Puoi usare il codice sopra per rimuovere l'oggetto dall'array ..
Rahul R.

1
Ben fatto. Aggiungerò questo alla mia cintura degli attrezzi
abyrne85,

un'altra cosa che voglio, ci saranno pulsanti separati per ogni oggetto nella matrice. se voglio cancellare quel particolare oggetto nel pulsante dell'array cliccato e che dovrebbe essere spostato su un altro array secondario. come farlo . ho usato angular js ng-repeat per generare oggetti. mi potete aiutare
Thilak Raj,

1
Adoro questo suggerimento ES5, in quanto può anche essere scritto in un modo più breveitems.splice(items.findIndex(i => i.id === "abc"), 1)
bramchi

27

findIndex funziona per i browser moderni:

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

Mi piace questa risposta moderna, tranne per il fatto che il tuo codice non
rileva

2
risposta molto semplice rispetto ad altri e funziona bene.
arun

risposta semplice ma potente
Shelly,

15

Per eliminare un oggetto dal suo id in un determinato array;

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

10

Se si desidera rimuoverlo dall'array esistente e non crearne uno nuovo, provare:

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

7
si noti che questa risposta richiede la libreria di sottolineatura
JoshuaDavid,

2
Non lo consiglierei perché se l'elemento non viene trovato _.indexOf restituirà -1 => items.splice (-1,1)
user1441287

6

Ripeti in ordine inverso diminuendo iper evitare il problema:

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

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

Oppure usa filter:

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


4

Solo JavaScript nativo per favore.

In alternativa, soluzione più "funzionale", lavorando su ECMAScript 5, è possibile utilizzare:

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

Secondo la definizione di "Array.prototype.reduceRight" nell'ECMA-262 :

reduceRight non muta direttamente l'oggetto su cui viene chiamato ma l'oggetto può essere mutato dalle chiamate a callbackfn .

Quindi questo è un uso valido di reduceRight.


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

secondo la tua risposta sarà così. quando si fa clic su un oggetto particolare, inviare l'indice nel parametro per la funzione di eliminazione. Questo semplice codice funzionerà come un fascino.

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

1
Grazie a questo ha aiutato molto :)
RAJESH KUMAR ARUMUGAM

1

con filtro e indice

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

con filtro e include

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

0

Se ti piacciono i parametri brevi e auto-descrittivi o se non vuoi usare splicee vai con un filtro diretto o se sei semplicemente una persona SQL come me:

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

E un esempio di utilizzo:

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

È possibile utilizzare filter. Questo metodo restituisce sempre l'elemento se la condizione è vera. Quindi, se si desidera rimuovere per ID, è necessario mantenere tutti gli elementi che non corrispondono con l'id specificato. Ecco un esempio:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.