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.

Dan Kanze
fonte
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));
Ry-
fonte
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);
parlamento
fonte
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

Rahul R.
fonte
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);
fatlinesofcode
fonte
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);
Naresh Chennuri
fonte
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);
user2704940
fonte
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;
});
Felix Rabe
fonte
5

Verifique isso usando o filtro Set e ES6.

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

Aqui está o JsFiddle: https://jsfiddle.net/jsq0a0p1/1/

Miroslav Savovski
fonte
1
Funciona perfeitamente!
Antoni Kepinski
Abordagem mais moderna e elegante na minha opinião.
AC Patrice
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.

Sylvain Leroux
fonte
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);
    }
}
Subhojit Mondal
fonte
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));
user3437231
fonte
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)
Mehmet Kaplan
fonte
-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)

David Benitez Riba
fonte