eliminar objetos de la matriz por propiedad del objeto


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

¿Cómo elimino un objeto de la matriz haciendo coincidir la propiedad del objeto?

Solo JavaScript nativo por favor.

Tengo problemas para usar el empalme porque la longitud disminuye con cada eliminación. El uso de clones y empalmes en el índice original todavía te deja con el problema de la disminución de la longitud.


1
El bucle hacia atrás debería solucionar el problema del cambio en la longitud
Ian

1
Es una pena que no haya una forma estándar adecuada para eliminar elementos de una matriz de objetos. No es de extrañar que haya tantos guiones de terceros. Es una cosa básica.
guitarlass

Respuestas:


155

¿Supongo que usaste splicealgo como esto?

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

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

Todo lo que necesita hacer para corregir el error es disminuir ila próxima vez (y hacer un bucle hacia atrás también es una opción):

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

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

Para evitar eliminaciones en tiempo lineal, puede escribir elementos de matriz que desee mantener sobre la matriz:

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;

y para evitar búsquedas de tiempo lineal en un tiempo de ejecución moderno, puede usar un conjunto de 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;

que se puede envolver en una buena función:

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

Si no necesita hacerlo en su lugar, eso es Array#filter:

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

79

Puede eliminar un elemento por una de sus propiedades sin usar ninguna biblioteca de terceros como esta:

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

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

1
Esta es una respuesta realmente elegante.
Scott Silvi,

Otra cosa que quiero, habrá botones separados para cada objeto en la matriz. si quiero eliminar ese objeto en particular en el botón de matriz, haga clic y eso debería moverse a otra matriz secundaria. cómo hacerlo . He usado angular js ng-repeat para generar elementos. ¿me pueden ayudar
Thilak Raj

Enfoque muy agradable y elegante. ¡prestigio! Solo una cosa por precaución; si el índice requerido no se encuentra en la matriz del mapa, devolverá -1; así, el empalme eliminará el último elemento.
mcy

15
O si te confunde la tilde en la última línea, puedes encontrar esto más claro: (removeIndex> = 0) && array.splice (removeIndex, 1);
wojjas

1
@parliament: ¿hay alguna documentación sobre la tilde en su ejemplo? Nunca he visto esto antes.
webdad3

43

Con lodash / subrayado:

Si desea modificar la matriz existente en sí, entonces tenemos que usar el empalme . Aquí está la forma un poco mejor / legible usando findWhere de subrayado / 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 superior

( sin lodash / subrayado )

Con ES5 en adelante, tenemos un findIndexmétodo en matriz, por lo que es fácil sin lodash / subrayado

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

(ES5 es compatible con casi todos los navegadores modernos)

Acerca de findIndex y su compatibilidad con el navegador


¿Cómo puedo eliminar todos los artículos en serie de objetos, pero necesito la devolución de llamada, así
Muhaimin

¿Qué quiere decir con devolución de llamada también, puede utilizar el código anterior para eliminar el objeto de la matriz ..
Rahul R.

1
Buena esa. Agregaré esto a mi cinturón de herramientas
abyrne85

Otra cosa que quiero, habrá botones separados para cada objeto en la matriz. si quiero eliminar ese objeto en particular en el botón de matriz, haga clic y eso debería moverse a otra matriz secundaria. cómo hacerlo . He usado angular js ng-repeat para generar elementos. ¿me pueden ayudar
Thilak Raj

1
Me encanta esta sugerencia de ES5, ya que incluso se puede escribir de una manera más cortaitems.splice(items.findIndex(i => i.id === "abc"), 1)
bramchi

27

findIndex funciona para navegadores modernos:

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

Me gusta esta respuesta moderna, excepto que su código no
detecta

2
Respuesta muy simple en comparación con otros y funciona bien.
Arun

Respuestas simples pero poderosas
Shelly

15

Para eliminar un objeto por su id en una matriz dada;

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

10

Si solo desea eliminarlo de la matriz existente y no crear uno nuevo, intente:

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

77

2
No recomendaría esto porque si no se encuentra el elemento _.indexOf devolverá -1 => items.splice (-1,1)
user1441287

6

Haga un bucle inverso al disminuir ipara evitar el problema:

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

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

O use filter:

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


4

Solo JavaScript nativo por favor.

Como alternativa, una solución más "funcional", trabajando en ECMAScript 5, puede usar:

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

De acuerdo con la definición de 'Array.prototype.reduceRight' en ECMA-262 :

reduceRight no muta directamente el objeto en el que se llama, pero el objeto puede ser mutado por las llamadas a callbackfn .

Entonces este es un uso válido de reduceRight.


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

según su respuesta será así. Cuando hace clic en algún objeto en particular, envíe el índice en el parámetro para la función Eliminarme. Este código simple funcionará como encanto.

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

1
Gracias esto ayudó mucho :)
RAJESH KUMAR ARUMUGAM

1

con filtro e index

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

con filtro e incluye

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

0

Si le gustan los parámetros breves y autodescriptivos o si no desea usar splicee ir con un filtro directo o si simplemente es una persona SQL como yo:

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

Y una muestra de uso:

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

Puedes usar filter. Este método siempre devuelve el elemento si la condición es verdadera. Entonces, si desea eliminar por identificación, debe mantener todo el elemento que no coincida con la identificación dada. Aquí hay un ejemplo:

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.