Não parece haver uma maneira de estender uma matriz JavaScript existente com outra matriz, ou seja, emular o extend
método do Python .
Eu quero alcançar o seguinte:
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
Eu sei que existe um a.concat(b)
método, mas ele cria uma nova matriz em vez de simplesmente estender a primeira. Eu gostaria de um algoritmo que funcione eficientemente quando a
for significativamente maior que b
(isto é, um que não copie a
).
Nota: Esta não é uma duplicata de Como acrescentar algo a uma matriz? - o objetivo aqui é adicionar todo o conteúdo de uma matriz à outra e fazê-lo "no lugar", ou seja, sem copiar todos os elementos da matriz estendida.
javascript
arrays
concatenation
DzinX
fonte
fonte
a.push(...b)
. O conceito é semelhante à resposta principal, mas atualizado para o ES6.Respostas:
O
.push
método pode receber vários argumentos. Você pode usar o operador spread para passar todos os elementos da segunda matriz como argumentos para.push
:Se o seu navegador não suportar o ECMAScript 6, você poderá usar
.apply
:Ou talvez, se você acha mais claro:
Observe que todas essas soluções falharão com um erro de estouro de pilha se a matriz
b
for muito longa (o problema começa em cerca de 100.000 elementos, dependendo do navegador).Se você não pode garantir que
b
seja curto o suficiente, use uma técnica padrão baseada em loop descrita na outra resposta.fonte
push
método da matriz pode levar qualquer número de argumentos, que são empurrados para a parte de trás da matriz. O mesmoa.push('x', 'y', 'z')
vale para uma chamada que se estenderáa
por 3 elementos.apply
é um método de qualquer função que pega uma matriz e usa seus elementos como se todos fossem dados explicitamente como elementos posicionais para a função. Assima.push.apply(a, ['x', 'y', 'z'])
também estenderia a matriz em 3 elementos. Além disso,apply
assume um contexto como o primeiro argumento (passamosa
novamente para o qual anexara
).[].push.apply(a, b)
.Atualização 2018 : Uma resposta melhor é a mais recente de uma mina :
a.push(...b)
. Não vote mais nessa, pois ela nunca respondeu à pergunta, mas foi um hack de 2015 em torno do primeiro hit no Google :)Para aqueles que simplesmente pesquisaram "JavaScript array extend" e chegaram aqui, você pode muito bem usar
Array.concat
.O Concat retornará uma cópia da nova matriz, pois o iniciador de threads não desejava. Mas você pode não se importar (certamente, para a maioria dos usos, isso será bom).
Há também um bom açúcar ECMAScript 6 para isso na forma do operador de propagação:
(Ele também copia.)
fonte
arr.push(...arr2)
resposta seja mais nova e melhor e uma resposta tecnicamente correta (tm) a essa pergunta em particular.Você deve usar uma técnica baseada em loop. Outras respostas nesta página baseadas no uso
.apply
podem falhar em matrizes grandes.Uma implementação baseada em loop bastante concisa é:
Você pode fazer o seguinte:
A resposta do DzinX (usando push.apply) e outros
.apply
métodos baseados falham quando a matriz que estamos anexando é grande (testes mostram que para mim grandes são> 150.000 entradas aproximadamente no Chrome e> 500.000 entradas no Firefox). Você pode ver esse erro ocorrendo neste jsperf .Ocorre um erro porque o tamanho da pilha de chamadas é excedido quando 'Function.prototype.apply' é chamado com uma matriz grande como o segundo argumento. (MDN tem uma observação sobre os perigos de exceder o tamanho da pilha de chamadas usando Function.prototype.apply - consulte a seção "funções aplicáveis e incorporadas".)
Para uma comparação de velocidade com outras respostas nesta página, consulte este jsperf (graças ao EaterOfCode). A implementação baseada em loop é semelhante em velocidade ao uso
Array.push.apply
, mas tende a ser um pouco mais lenta queArray.slice.apply
.Curiosamente, se a matriz que você está anexando é escassa, o
forEach
método baseado acima pode tirar vantagem da escassez e superar os.apply
métodos baseados; confira este jsperf se você quiser testar isso por si mesmo.A propósito, não fique tentado (como eu estava!) A reduzir ainda mais a implementação do forEach para:
porque isso produz resultados de lixo! Por quê? Porque
Array.prototype.forEach
fornece três argumentos para a função que chama - estes são: (element_value, element_index, source_array). Tudo isso será enviado para sua primeira matriz para cada iteraçãoforEach
se você usar "forEach (this.push, this)"!fonte
.push.apply
é realmente muito mais rápido que.forEach
na v8, o mais rápido ainda é um loop inline..forEach
é mais rápido que.push.apply
no Chrome / Chromium (em todas as versões desde a v25). Não pude testar a v8 isoladamente, mas se você tiver, vincule seus resultados. Veja jsperf: jsperf.com/array-extending-push-vs-concat/5undefined
,.forEach
os ignorará, tornando-o o mais rápido..splice
é realmente o mais rápido ?! jsperf.com/array-extending-push-vs-concat/18Sinto que o mais elegante hoje em dia é:
O artigo da MDN sobre o operador de spread menciona essa maneira agradável e açucarada no ES2015 (ES6):
Observe que
arr2
não pode ser enorme (mantenha-o abaixo de cerca de 100.000 itens), porque a pilha de chamadas transborda, conforme resposta do jcdude.fonte
arr1.push(arr2)
. Isso pode ser um problema, portantoarr1 = []; arr2=['a', 'b', 'd']; arr1.push(arr2)
o resultado é uma matriz de matrizes, emarr1 == [['a','b','d']]
vez de duas matrizes combinadas. É um erro fácil de cometer. Prefiro sua segunda resposta abaixo por esse motivo. stackoverflow.com/a/31521404/4808079.concat
o segundo argumento não deve ser uma matriz. Isso pode ser conseguido combinando o operador de spread comconcat
, por exemplo,arr1.push(...[].concat(arrayOrSingleItem))
Primeiro, algumas palavras sobre
apply()
JavaScript para ajudar a entender por que usamos:O Push espera uma lista de itens a serem adicionados à matriz. O
apply()
método, no entanto, aceita os argumentos esperados para a chamada de função como uma matriz. Isso nos permite facilmentepush
os elementos de uma matriz em outra matriz com opush()
método embutido .Imagine que você tem estas matrizes:
e simplesmente faça o seguinte:
O resultado será:
O mesmo pode ser feito no ES6 usando o operador de spread ("
...
") assim:Mais curto e melhor, mas não totalmente suportado em todos os navegadores no momento.
Além disso, se você deseja mover tudo da matriz
b
para oa
esvaziamentob
no processo, você pode fazer isso:e o resultado será o seguinte:
fonte
while (b.length) { a.push(b.shift()); }
certo?Se você deseja usar o jQuery, há $ .merge ()
Exemplo:
Resultado: a =
[1, 2, 3, 4, 5]
fonte
jQuery.merge()
?Eu gosto do
a.push.apply(a, b)
método descrito acima e, se você quiser, pode sempre criar uma função de biblioteca como esta:e use assim
fonte
É possível fazer isso usando
splice()
:Mas apesar de ser mais feio, não é mais rápido que
push.apply
, pelo menos não no Firefox 3.0.fonte
Esta solução funciona para mim (usando o operador de propagação do ECMAScript 6):
fonte
Você pode criar um polyfill para estender como eu tenho abaixo. Ele será adicionado à matriz; no local e retorne a si próprio, para que você possa encadear outros métodos.
fonte
Combinando as respostas ...
fonte
Outra solução para mesclar mais de duas matrizes
Em seguida, ligue e imprima como:
A saída será:
Array [1, 2, 3, 4, 5, 6, 7]
fonte
A resposta é super simples.
O Concat atua de maneira muito semelhante à concatenação de strings JavaScript. Ele retornará uma combinação do parâmetro que você colocou na função concat no final da matriz na qual você chama a função. O ponto crucial é que você deve atribuir o valor retornado a uma variável ou ele se perde. Então por exemplo
fonte
Array.prototype.concat()
do MDN, isso retornará uma nova matriz , ela não será anexada à matriz existente, como o OP estava pedindo claramente.Use em
Array.extend
vez deArray.push
para> 150.000 registros.fonte
Super simples, não conta com operadores espalhados ou aplica, se isso é um problema.
Depois de executar alguns testes de desempenho, é muito lento, mas responde à pergunta em relação à não criação de uma nova matriz. O Concat é significativamente mais rápido, até o jQuery
$.merge()
grita.https://jsperf.com/merge-arrays19b/1
fonte
.forEach
e não.map
se não estiver usando o valor de retorno. Ele transmite melhor a intenção do seu código..map
mas você também pode fazerb.forEach(function(x) { a.push(x)} )
. Na verdade, eu adicionei isso ao teste jsperf e é um cabelo mais rápido que o mapa. Ainda super lento..map
aqui parece muito estranho. Seria como ligarb.filter(x => a.push(x))
. Funciona, mas confunde o leitor, implicando que algo está acontecendo quando não está..map()
faz e esse é o problema. Esse conhecimento me faria pensar que você precisa da matriz resultante, caso contrário, seria uma boa coisa usar.forEach()
o cauteloso leitor sobre os efeitos colaterais da função de retorno de chamada. A rigor, sua solução cria uma matriz adicional de números naturais (resultados depush
), enquanto a pergunta afirma: "sem criar uma nova matriz".