remover objetos da matriz por propriedade do 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

Como faço para remover um objeto da matriz, correspondendo à propriedade do objeto?

Somente JavaScript nativo, por favor.

Estou tendo problemas para usar a emenda porque o comprimento diminui a cada exclusão. Usar clone e splicing no índice original ainda deixa você com o problema de diminuir o comprimento.


1
Looping para trás deve corrigir a mudança no problema comprimento
— Ian

1
É uma pena que não exista uma maneira adequada e padrão de remover itens de uma matriz de objetos. Não é de admirar que haja tantos scripts de terceiros. É uma coisa básica.
— guitarlass

Respostas:


155

Eu suponho que você usou splicealgo assim?

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

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

Tudo o que você precisa fazer para corrigir o erro é diminuir ipara a próxima vez (e fazer um loop para trás também é uma opção):

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 exclusões de tempo linear, você pode escrever os elementos da matriz que deseja manter sobre a 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;

e para evitar pesquisas de tempo linear em um tempo de execução moderno, você pode usar um 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 pode ser envolvido em uma boa função:

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 você não precisa fazer isso no lugar, é Array#filter:

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

79

Você pode remover um item por uma de suas propriedades sem usar nenhuma biblioteca de terceiros como esta:

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

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

1
Esta é uma resposta realmente elegante.
— Scott Silvi

Outra coisa que eu quero, haverá botões separados para cada objeto na matriz. se eu quiser excluir aquele objeto em particular no botão da matriz clicou e isso deve ser movido para outra matriz secundária. como fazer isso . Eu usei js angular ng-repeat para gerar itens. você pode me ajudar
— Thilak Raj

abordagem muito agradável e elegante. parabéns! Apenas uma coisa para cautela; se o índice necessário não for encontrado na matriz do mapa, ele retornará -1; assim, a emenda removerá o último elemento.
— Mcy

15
Ou, se você ficar confuso com o til da última linha, poderá achar isso mais claro: (removeIndex> = 0) && array.splice (removeIndex, 1);
— Wojjas # 11/16

1
@parl Parliament - existe alguma documentação sobre o til no seu exemplo? Eu nunca vi isso antes.
— Webdad3

43

Com lodash / sublinhado:

Se você deseja modificar a própria matriz existente, precisamos usar a emenda . Aqui está a maneira um pouco melhor / legível usando findWhere de 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);

Com ES5 ou superior

( sem lodash / sublinhado )

Com o ES5 em diante, temos o findIndexmétodo no array, portanto é fácil sem lodash / sublinhado

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

(O ES5 é suportado em quase todos os navegadores morden)

Sobre o findIndex e sua compatibilidade com o navegador


como faço para remover todos os itens na matriz de objeto, mas eu preciso do retorno de chamada bem
— Muhaimin

o que você quer dizer com retorno de chamada, bem como, você pode usar o código acima para remover o objeto do conjunto ..
— Rahul R.

1
Agradável. Eu adicionarei isso ao meu
— cinto de

Outra coisa que eu quero, haverá botões separados para cada objeto na matriz. se eu quiser excluir aquele objeto em particular no botão da matriz clicou e isso deve ser movido para outra matriz secundária. como fazer isso . Eu usei js angular ng-repeat para gerar itens. você pode me ajudar
— Thilak Raj

1
Amo essa sugestão do ES5, pois ela pode até ser escrita de maneira mais curtaitems.splice(items.findIndex(i => i.id === "abc"), 1)
— bramchi

27

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

Eu gosto desta resposta moderna, exceto o código não pegar o caso quando index = -1
— rmcsharry

2
resposta muito simples em comparação com os outros e funciona muito bem.
— Arun

resposta simples, mas poderosa
— Shelly

15

Para excluir um objeto por seu ID em determinada matriz;

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

10

Se você apenas deseja removê-lo da matriz existente e não criar uma nova, tente:

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

7
aviso de que esta resposta exige que o sublinhado biblioteca
— JoshuaDavid

2
Eu não recomendaria isso porque, se o elemento não for encontrado, _.indexOf retornará -1 => items.splice (-1,1)
— user1441287

6

Faça um loop invertido decrementando ipara evitar o problema:

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

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

Ou use filter:

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


4

Somente JavaScript nativo, por favor.

Como uma solução alternativa, mais "funcional", trabalhando no ECMAScript 5, você pode 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 acordo com a definição de 'Array.prototype.reduceRight' no ECMA-262 :

redRight não altera diretamente o objeto no qual é chamado, mas o objeto pode ser alterado pelas chamadas para callbackfn .

Portanto, este é um 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

conforme sua resposta será assim. quando você clica em algum objeto específico, envia o índice no parâmetro para a função excluir-me. Este código simples funcionará como charme.

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

1
Thnaks isso ajudou muito :)
— Rajesh Kumar ARUMUGAM

1

com filter & indexOf

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

com filtro e inclui

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

0

Se você gosta de parâmetros curtos e auto-descritivos ou se não deseja usar splicee usar um filtro direto ou se é simplesmente uma pessoa SQL como eu:

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 uma amostra 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

Você pode usar filter. Este método sempre retorna o elemento se a condição for verdadeira. Portanto, se você deseja remover por ID, deve manter todo o elemento que não corresponde ao ID fornecido. Aqui está um exemplo:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.