Exclusão de elementos de matriz em JavaScript - exclusão vs emenda

1334

Qual é a diferença entre usar o deleteoperador no elemento da matriz em vez de usar o Array.splicemétodo ?

Por exemplo:

myArray = ['a', 'b', 'c', 'd'];

delete myArray[1];
//  or
myArray.splice (1, 1);

Por que usar o método de emenda se eu posso excluir elementos da matriz como posso com objetos?

lYriCAlsSH
fonte
3
Para .spliceloops in, dê uma olhada nesta pergunta: Exclua da matriz em javascript .
Rob W
6
@andynormancx Sim, mas essa resposta foi postada no dia seguinte e obteve muitos mais votos - eu diria que é melhor escrito, deve ser isso.
Camilo Martin #
@andynormancx - Não parece ser uma duplicata exata. A pergunta que você vinculou está basicamente perguntando por que excluir um elemento de uma matriz (tornando-o escasso) não reduzirá seu comprimento. Esta pergunta está pedindo as diferenças entre deletee Array.prototype.splice.
chharvey
@chharvey concordou, mais importante ainda: como essa pergunta pode ter sido publicada há 9 anos! Faz-me sentir velho por estar de volta aqui comentando sobre isso
andynormancx 13/03

Respostas:

1693

deleteexcluirá a propriedade do objeto, mas não reindexará a matriz nem atualizará seu comprimento. Isso faz com que pareça indefinido:

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> delete myArray[0]
  true
> myArray[0]
  undefined

Observe que, na verdade, ele não está definido como o valor undefined, mas a propriedade é removida da matriz, fazendo com que ela pareça indefinida. As ferramentas de desenvolvimento do Chrome tornam essa distinção clara ao imprimir emptyao registrar a matriz.

> myArray[0]
  undefined
> myArray
  [empty, "b", "c", "d"]

myArray.splice(start, deleteCount) na verdade remove o elemento, reindexa a matriz e altera seu comprimento.

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> myArray.splice(0, 2)
  ["a", "b"]
> myArray
  ["c", "d"]
Andy Hume
fonte
74
Na verdade, delete ele remove o elemento, mas não reindexa a matriz nem atualiza seu comprimento (o que já está implícito no primeiro, pois o comprimento é sempre o índice mais alto + 1).
Felix Kling
3
O JSlint não gosta da delete myArray[0]sintaxe dizendo " Esperava um operador e viu 'delete'. " spliceÉ recomendável usar .
Olho
21
@ Eye: Na verdade, o JSLint está apenas reclamando da falta de ponto e vírgula na linha anterior. E você realmente não pode recomendar um sobre o outro, uma vez que eles fazem coisas completamente diferentes ...
Ry-
3
"Excluir neste caso definirá apenas o elemento como indefinido:" Não, isso é totalmente incorreto. Há uma diferença fundamental entre delete myArray[0]e myArray[0] = undefined. No primeiro caso, a propriedade é removida totalmente do objeto da matriz. No segundo caso, a propriedade permanece com o valor undefined.
TJ Crowder
1
Para sua informação, as ferramentas de desenvolvimento do Chrome mostram a palavra-chave em emptyvez de undefinedmelhorar a distinção entre um elemento de matriz realmente excluído (ou não inicializado) versus um elemento com o valor real de undefined. Observe que, enquanto digo isso, quero dizer que apenas é exibido como emptye não se refere a um valor real chamado empty(que não existe).
chharvey
340

Método Array.remove ()

John Resig , criador do jQuery, criou um Array.removemétodo muito útil que eu sempre o uso em meus projetos.

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

e aqui estão alguns exemplos de como ele pode ser usado:

// Remove the second item from the array
array.remove(1);
// Remove the second-to-last item from the array
array.remove(-2);
// Remove the second and third items from the array
array.remove(1,2);
// Remove the last and second-to-last items from the array
array.remove(-2,-1);

John's website

Mohsen
fonte
4
+1 Para Array.remove (). Argumentos de seqüência no entanto, não está sendo feliz passadas (ao contrário da maioria dos métodos de matriz, por exemplo [1,2,3].slice('1'); // =[2,3]), por isso é mais seguro para alterá-lo paravar rest = this.slice(parseInt(to || from) + 1 || this.length);
Richard Inglis
1
@tomwrong, não há tópicos em javascript, e executa a função this.push.apply(this, rest), em seguida, retorna o valor que ele voltou
billy
59
Isso não responde à pergunta.
Ry-
16
Por que não usar apenas splice ()? O nome desta função, os nomes dos parâmetros e os resultados não são óbvios. Minha recomendação é tala apenas uso (index, comprimento) - (ver resposta de Andy Hume)
Auco
3
A função fornecida acima funciona conforme explicado, mas cria efeitos colaterais indesejados ao percorrer a matriz com for(var i in array)ciclo. Eu o removi e usei a emenda.
alexykot
104

Como delete remove apenas o objeto do elemento na matriz, o comprimento da matriz não muda. A emenda remove o objeto e reduz a matriz.

O código a seguir exibirá "a", "b", "undefined", "d"

myArray = ['a', 'b', 'c', 'd']; delete myArray[2];

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

Considerando que isso exibirá "a", "b", "d"

myArray = ['a', 'b', 'c', 'd']; myArray.splice(2,1);

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}
andynormancx
fonte
11
exemplo excelente, exceto a ambiguidade no segundo exemplo usando 1,1 - o primeiro 1 refere-se ao índice na matriz para iniciar a emenda, o segundo 1 é o número de elementos a serem removidos. Então, para remover 'c' da matriz original, usemyArray.splice(2,1)
iancoleman
68

Eu me deparei com essa pergunta enquanto tentava entender como remover todas as ocorrências de um elemento de uma matriz. Aqui está uma comparação de splicee deletepara remover todos 'c'os da itemsmatriz.

var items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  items.splice(items.indexOf('c'), 1);
}

console.log(items); // ["a", "b", "d", "a", "b", "d"]

items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  delete items[items.indexOf('c')];
}

console.log(items); // ["a", "b", undefined, "d", "a", "b", undefined, "d"]
Troy Harvey
fonte
10

splice funcionará com índices numéricos.

Considerando que deletepode ser usado contra outro tipo de índices.

exemplo:

delete myArray['text1'];
Gopal
fonte
9
Quando você diz "qualquer outro tipo de índice", não está mais falando de matrizes, mas de objetos, que é o que o OP está perguntando.
Yi Jiang
2
@YiJiang: Arrays são objetos. Indizes são propriedades. Não há diferença.
Bergi
9

Também vale a pena mencionar que a emenda só funciona em matrizes. (Não é possível confiar nas propriedades do objeto para seguir uma ordem consistente.)

Para remover o par de valores-chave de um objeto, excluir é realmente o que você deseja:

delete myObj.propName;     // , or:
delete myObj["propName"];  // Equivalent.
jtrick
fonte
delete não reordena as chaves da matriz, portanto: var arr = [1,2,3,4,5]; delete arr [3]; para (var i = 0; i <= comprimento arr.; i ++) console.log (arr [i]); exibirá resultados inesperados.
21816 Kristian Williams
Isso é verdade. Portanto, a menos que você queira deixar um item indefinido nesse local, NÃO use delete nas chaves de uma matriz! Eu originalmente adicionei este comentário para incluir uma referência do uso correto de delete.
jtrick
mas por que excluir lançará resultado inesperado ??
Alex
9

excluir Vs emenda

quando você exclui um item de uma matriz

var arr = [1,2,3,4]; delete arr[2]; //result [1, 2, 3:, 4]
console.log(arr)

quando você emenda

var arr = [1,2,3,4]; arr.splice(1,1); //result [1, 3, 4]
console.log(arr);

em caso de exclusão, o elemento é excluído, mas o índice permanece vazio

enquanto no caso do elemento de emenda é excluído e o índice de elementos de repouso é reduzido de acordo

Ashish Yadav
fonte
8

Como afirmado muitas vezes acima, o uso splice()parece ser um ajuste perfeito. Documentação na Mozilla:

O splice()método altera o conteúdo de uma matriz removendo elementos existentes e / ou adicionando novos elementos.

var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

myFish.splice(2, 0, 'drum'); 
// myFish is ["angel", "clown", "drum", "mandarin", "sturgeon"]

myFish.splice(2, 1); 
// myFish is ["angel", "clown", "mandarin", "sturgeon"]

Sintaxe

array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

Parâmetros

começar

Índice no qual começar a alterar a matriz. Se maior que o comprimento da matriz, o índice inicial real será definido como o comprimento da matriz. Se negativo, começará muitos elementos a partir do final.

deleteCount

Um número inteiro indicando o número de elementos antigos da matriz a serem removidos. Se deleteCount for 0, nenhum elemento será removido. Nesse caso, você deve especificar pelo menos um novo elemento. Se deleteCount for maior que o número de elementos restantes na matriz iniciando no início, todos os elementos até o final da matriz serão excluídos.

Se deleteCount for omitido, deleteCount será igual a (arr.length - start).

item1, item2, ...

Os elementos a serem adicionados à matriz, começando no índice inicial. Se você não especificar nenhum elemento, splice()apenas os elementos serão removidos da matriz.

Valor de retorno

Uma matriz contendo os elementos excluídos. Se apenas um elemento for removido, uma matriz de um elemento será retornada. Se nenhum elemento for removido, uma matriz vazia será retornada.

[...]

serv-inc
fonte
@ downvoter: por que o voto negativo? gostaria de explicar, ou não?
serv-inc #
7

delete age como uma situação não real, apenas remove o item, mas o comprimento da matriz permanece o mesmo:

exemplo do terminal do nó:

> var arr = ["a","b","c","d"];
> delete arr[2]
true
> arr
[ 'a', 'b', , 'd', 'e' ]

Aqui está uma função para remover um item de uma matriz por índice, usando slice () , ela recebe o arr como o primeiro argumento e o índice do membro que você deseja excluir como o segundo argumento. Como você pode ver, ele realmente exclui o membro da matriz e reduz o comprimento da matriz em 1

function(arr,arrIndex){
    return arr.slice(0,arrIndex).concat(arr.slice(arrIndex + 1));
}

O que a função acima faz é levar todos os membros até o índice e todos os membros após o índice, concatená-los juntos e retornar o resultado.

Aqui está um exemplo usando a função acima como um módulo de nó, pois o terminal será útil:

> var arr = ["a","b","c","d"]
> arr
[ 'a', 'b', 'c', 'd' ]
> arr.length
4 
> var arrayRemoveIndex = require("./lib/array_remove_index");
> var newArray = arrayRemoveIndex(arr,arr.indexOf('c'))
> newArray
[ 'a', 'b', 'd' ] // c ya later
> newArray.length
3

observe que isso não funcionará em uma matriz com dupes, porque indexOf ("c") obterá a primeira ocorrência e somente emendar e remover o primeiro "c" encontrado.

med116
fonte
6

Se você deseja iterar uma matriz grande e excluir elementos seletivamente, seria caro chamar splice () para cada exclusão, porque splice () precisaria re-indexar os elementos subseqüentes a cada vez. Como matrizes são associativas em Javascript, seria mais eficiente excluir os elementos individuais e indexar novamente a matriz posteriormente.

Você pode fazer isso criando uma nova matriz. por exemplo

function reindexArray( array )
{
       var result = [];
        for( var key in array )
                result.push( array[key] );
        return result;
};

Mas não acho que você possa modificar os valores-chave na matriz original, o que seria mais eficiente - parece que você precisará criar uma nova matriz.

Observe que você não precisa verificar as entradas "indefinidas", pois elas realmente não existem e o loop for não as retorna. É um artefato da impressão em matriz que os exibe como indefinidos. Eles não parecem existir na memória.

Seria bom se você pudesse usar algo como slice (), que seria mais rápido, mas não é re-indexado. Alguém sabe de uma maneira melhor?


Na verdade, você provavelmente pode fazer isso da seguinte maneira, o que provavelmente é mais eficiente, em termos de desempenho:

reindexArray : function( array )
{
    var index = 0;                          // The index where the element should be
    for( var key in array )                 // Iterate the array
    {
        if( parseInt( key ) !== index )     // If the element is out of sequence
        {
            array[index] = array[key];      // Move it to the correct, earlier position in the array
            ++index;                        // Update the index
        }
    }

    array.splice( index );  // Remove any remaining elements (These will be duplicates of earlier items)
},
Mike T
fonte
Eu acredito no índice ++; precisa acontecer fora do 'se'. Fazendo edição
mishal153
6

você pode usar algo assim

var my_array = [1,2,3,4,5,6];
delete my_array[4];
console.log(my_array.filter(function(a){return typeof a !== 'undefined';})); // [1,2,3,4,6]

Zeeshan Saleem
fonte
isso é mais intuitivo do que slicese você vier de um plano de fundo funcional (provavelmente menos eficiente, no entanto).
jethro
3

Por que não apenas filtrar? Eu acho que é a maneira mais clara de considerar as matrizes em js.

myArray = myArray.filter(function(item){
    return item.anProperty != whoShouldBeDeleted
});
Asqan
fonte
Que tal uma matriz com centenas (senão milhares) de registros em que apenas três deles precisam ser removidos?
Joel Hernandez
bom ponto. Eu uso esse método para matrizes esparsas cujo comprimento não exceda 200 ou 300 e tem um desempenho muito bom. No entanto, acho que bibliotecas como o sublinhado devem ser preferidas se você precisar gerenciar matrizes tão maiores.
Asqan
1
No entanto, parece muito melhor do que deleteou slicepara mim.
Juneyoung Oh
3

A diferença pode ser observada registrando o comprimento de cada matriz após a aplicação do deleteoperador e do splice()método. Por exemplo:

operador de exclusão

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];

console.log(trees); // ["redwood", "bay", "cedar", empty, "maple"]
console.log(trees.length); // 5

O deleteoperador remove o elemento da matriz, mas o "espaço reservado" do elemento ainda existe. oakfoi removido, mas ainda ocupa espaço na matriz. Por esse motivo, o comprimento da matriz permanece 5.

método splice ()

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);

console.log(trees); // ["redwood", "bay", "cedar", "maple"]
console.log(trees.length); // 4

O splice()método remove completamente o valor de destino e o "espaço reservado" também. oakfoi removido, bem como o espaço usado para ocupar na matriz. O comprimento da matriz é agora 4.

underthecode
fonte
2
function remove_array_value(array, value) {
    var index = array.indexOf(value);
    if (index >= 0) {
        array.splice(index, 1);
        reindex_array(array);
    }
}
function reindex_array(array) {
   var result = [];
    for (var key in array) {
        result.push(array[key]);
    }
    return result;
}

exemplo:

var example_arr = ['apple', 'banana', 'lemon'];   // length = 3
remove_array_value(example_arr, 'banana');

banana é excluída e comprimento da matriz = 2

Terry Lin
fonte
2

São coisas diferentes que têm propósitos diferentes.

spliceé específico da matriz e, quando usado para excluir, remove as entradas da matriz e move todas as entradas anteriores para cima para preencher a lacuna. (Também pode ser usado para inserir entradas, ou ambas ao mesmo tempo.) spliceAlterará o lengthda matriz (supondo que não seja uma chamada não operacional:) theArray.splice(x, 0).

deletenão é específico da matriz; Ele foi projetado para uso em objetos: remove uma propriedade (par chave / valor) do objeto em que você a usa. Aplica-se apenas a matrizes porque matrizes padrão (por exemplo, não digitadas) em JavaScript não são realmente matrizes *, são objetos com tratamento especial para determinadas propriedades, como aquelas cujos nomes são "índices de matriz" (que são definido como nomes de sequência "... cujo valor numérico iestá no intervalo +0 ≤ i < 2^32-1") e length. Quando você usa deletepara remover uma entrada de matriz, tudo o que faz é remover a entrada; ele não move outras entradas que o seguem para preencher a lacuna e, portanto, a matriz se torna "esparsa" (algumas entradas estão ausentes totalmente). Não tem efeito length.

Algumas das respostas atuais para esta pergunta afirmam incorretamente que o uso de delete"define a entrada como undefined". Isso não está correto. Ele remove a entrada (propriedade) inteiramente, deixando uma lacuna.

Vamos usar algum código para ilustrar as diferenças:

console.log("Using `splice`:");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a.splice(0, 1);
console.log(a.length);            // 4
console.log(a[0]);                // "b"

console.log("Using `delete`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
delete a[0];
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // false
console.log(a.hasOwnProperty(0)); // false

console.log("Setting to `undefined`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a[0] = undefined;
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // true
console.log(a.hasOwnProperty(0)); // true


* (esse é um post no meu blog anêmico)

TJ Crowder
fonte
2

Atualmente, existem duas maneiras de fazer isso

  1. usando splice ()

    arrayObject.splice(index, 1);

  2. usando delete

    delete arrayObject[index];

Mas eu sempre sugiro usar emenda para objetos de matriz e excluir para atributos de objeto, porque excluir não atualiza o comprimento da matriz.

imal hasaranga perera
fonte
1

OK, imagine que temos esta matriz abaixo:

const arr = [1, 2, 3, 4, 5];

Vamos excluir primeiro:

delete arr[1];

e este é o resultado:

[1, empty, 3, 4, 5];

esvaziar! e vamos entender:

arr[1]; //undefined

Então, significa apenas o valor excluído e está indefinido agora; portanto, o comprimento é o mesmo, também retornará verdadeiro ...

Vamos redefinir nossa matriz e fazê-lo com emenda desta vez:

arr.splice(1, 1);

e este é o resultado desta vez:

[1, 3, 4, 5];

Como você vê, o comprimento da matriz mudou e agora arr[1]é 3 ...

Além disso, isso retornará o item excluído em uma matriz, [3]neste caso ...

Alireza
fonte
1

Outros já compararam corretamente deletecom splice.

Outra comparação interessante é deletecontra undefined: um item de matriz excluído usa menos memória do que aquele que acabou de ser definido undefined;

Por exemplo, este código não será concluído:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Produz este erro:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Então, como você pode ver, undefinedocupa realmente a memória heap.

No entanto, se você também deleteo item ário (em vez de apenas configurá-lo como undefined), o código será concluído lentamente:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Estes são exemplos extremos, mas eles enfatizam deleteque nunca vi ninguém mencionar em lugar algum.

Lonnie Best
fonte
1

Se você tiver uma matriz pequena, poderá usar filter:

myArray = ['a', 'b', 'c', 'd'];
myArray = myArray.filter(x => x !== 'b');
Emir Mamashov
fonte
0

A maneira mais fácil é provavelmente

var myArray = ['a', 'b', 'c', 'd'];
delete myArray[1]; // ['a', undefined, 'c', 'd']. Then use lodash compact method to remove false, null, 0, "", undefined and NaN
myArray = _.compact(myArray); ['a', 'c', 'd'];

Espero que isto ajude. Referência: https://lodash.com/docs#compact

Prashanth
fonte
1
Alguém deveria tropeçar nisso pensando em compact... não há necessidade de lodash. TentemyArray.filter(function(n){return n;})
dat
0

Para quem quiser usar o Lodash pode usar: myArray = _.without(myArray, itemToRemove)

Ou como eu uso no Angular2

import { without } from 'lodash';
...
myArray = without(myArray, itemToRemove);
...
Ricky Levi
fonte
0

delete : delete excluirá a propriedade do objeto, mas não reindexará a matriz nem atualizará seu comprimento. Isso faz com que pareça indefinido:

emenda : na verdade remove o elemento, reindexa a matriz e altera seu comprimento.

Excluir elemento da última

arrName.pop();

Excluir elemento do primeiro

arrName.shift();

Excluir do meio

arrName.splice(starting index,number of element you wnt to delete);

Ex: arrName.splice(1,1);

Excluir um elemento do último

arrName.splice(-1);

Excluir usando o número de índice da matriz

 delete arrName[1];
Srikrushna
fonte
0

Se o elemento desejado a ser excluído estiver no meio (digamos que queremos excluir 'c', cujo índice é 1), você pode usar:

var arr = ['a','b','c'];
var indexToDelete = 1;
var newArray = arr.slice(0,indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))
Idan Gozlan
fonte
0

IndexOfaceita também um tipo de referência. Suponha o seguinte cenário:

var arr = [{item: 1}, {item: 2}, {item: 3}];
var found = find(2, 3); //pseudo code: will return [{item: 2}, {item:3}]
var l = found.length;

while(l--) {
   var index = arr.indexOf(found[l])
      arr.splice(index, 1);
   }
   
console.log(arr.length); //1

Diferentemente:

var item2 = findUnique(2); //will return {item: 2}
var l = arr.length;
var found = false;
  while(!found && l--) {
  found = arr[l] === item2;
}

console.log(l, arr[l]);// l is index, arr[l] is the item you look for
Roland
fonte
-1
function deleteFromArray(array, indexToDelete){
  var remain = new Array();
  for(var i in array){
    if(array[i] == indexToDelete){
      continue;
    }
    remain.push(array[i]);
  }
  return remain;
}

myArray = ['a', 'b', 'c', 'd'];
deleteFromArray(myArray , 0);

// resultado: myArray = ['b', 'c', 'd'];

Eyad Farra
fonte
@ChrisDennis why? (sem sarcasmo ou malícia destina, esta é uma pergunta sincera)
Chris Bier
Além do fato de que essa resposta não aborda a questão do OP #
Chris Bier