Valores de matriz de push de JavaScript em outra matriz

Eu tenho um array array de dataArray javascript que eu quero empurrar para um novo array newArray . Exceto eu não quero newArray[0] para ser dataArray . Eu quero empurrar todos os valores para o novo array:

 var newArray = []; newArray.pushValues(dataArray1); newArray.pushValues(dataArray2); // ... 

ou melhor ainda:

 var newArray = new Array ( dataArray1.values(), dataArray2.values(), // ... where values() (or something equivalent) would push the individual values into the array, rather than the array itself ); 

Então agora o novo array contém todos os valores dos arrays de dados individuais. Existe alguma abreviação como pushValues disponível, então eu não tenho que iterar sobre cada dataArray individual, adicionando os valores 1 por 1?

Use a function concat , assim:

 var arrayA = [1, 2]; var arrayB = [3, 4]; var newArray = arrayA.concat(arrayB); 

O valor de newArray será [1, 2, 3, 4] ( arrayA e arrayB permanecem inalterados; a concat cria e retorna uma nova matriz para o resultado).

Desde que suas matrizes não sejam enormes (veja abaixo), você pode usar o método push() da matriz à qual você deseja acrescentar valores. push() pode receber vários parâmetros para que você possa usar o método apply() para passar a matriz de valores a serem empurrados como uma lista de parâmetros da function. Isso tem a vantagem de usar o concat() de adicionar elementos ao array no lugar, em vez de criar um novo array.

No entanto, parece que para grandes matrizes (da ordem de 100.000 membros ou mais), esse truque pode falhar . Para esses arrays, usar um loop é uma abordagem melhor. Consulte https://stackoverflow.com/a/17368101/96100 para obter detalhes.

 var newArray = []; newArray.push.apply(newArray, dataArray1); newArray.push.apply(newArray, dataArray2); 

Você pode querer generalizar isso em uma function:

 function pushArray(arr, arr2) { arr.push.apply(arr, arr2); } 

… ou adicione-o ao protótipo da Array :

 Array.prototype.pushArray = function(arr) { this.push.apply(this, arr); }; var newArray = []; newArray.pushArray(dataArray1); newArray.pushArray(dataArray2); 

… ou emule o método push() , permitindo vários parâmetros usando o fato de que concat() , como push() , permite vários parâmetros:

 Array.prototype.pushArray = function() { this.push.apply(this, this.concat.apply([], arguments)); }; var newArray = []; newArray.pushArray(dataArray1, dataArray2); 

Aqui está uma versão baseada em loop do último exemplo, adequada para grandes matrizes e todos os principais navegadores, incluindo o IE < = 8:

 Array.prototype.pushArray = function() { var toPush = this.concat.apply([], arguments); for (var i = 0, len = toPush.length; i < len; ++i) { this.push(toPush[i]); } }; 

Vou adicionar mais uma resposta “à prova do futuro”

No ECMAScript 6, você pode usar o operador spread :

 var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1.push(...arr2); 

O operador de spread ainda não está incluído nos principais navegadores. Para a compatibilidade atual, veja esta tabela de compatibilidade (atualizada continuamente).

Você pode, no entanto, usar o operador de distribuição com o Babel.js .

editar:

Veja a resposta de Jack Giffin abaixo para mais comentários sobre o desempenho. Parece concat ainda é melhor e mais rápido que o operador de spread.

Encontrou uma maneira elegante do MDN

 var vegetables = ['parsnip', 'potato']; var moreVegs = ['celery', 'beetroot']; // Merge the second array into the first one // Equivalent to vegetables.push('celery', 'beetroot'); Array.prototype.push.apply(vegetables, moreVegs); console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot'] 

Ou você pode usar o recurso de spread operator do ES6:

 let fruits = [ 'apple', 'banana']; const moreFruits = [ 'orange', 'plum' ]; fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"] 
 var a=new Array('a','b','c'); var b=new Array('d','e','f'); var d=new Array('x','y','z'); var c=a.concat(b,d) 

Isso resolve o seu problema?

O seguinte parece mais simples para mim:

 var newArray = dataArray1.slice(); newArray.push.apply(newArray, dataArray2); 

Como “push” leva um número variável de argumentos, você pode usar o método apply da function push para empurrar todos os elementos de outro array. Ele constrói uma chamada para push usando seu primeiro argumento (“newArray” aqui) como “this” e os elementos da matriz como os argumentos restantes.

A slice na primeira instrução obtém uma cópia da primeira matriz, portanto, você não a modifica.

Atualização Se você estiver usando uma versão do javascript com fatia disponível, você pode simplificar a expressão push para:

 newArray.push(...dataArray2) 

Há várias respostas sobre o Array.prototype.push.apply . Aqui está um exemplo claro:

 var dataArray1 = [1, 2]; var dataArray2 = [3, 4, 5]; var newArray = [ ]; Array.prototype.push.apply(newArray, dataArray1); // newArray = [1, 2] Array.prototype.push.apply(newArray, dataArray2); // newArray = [1, 2, 3, 4, 5] console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5] 

Com o JavaScript ES6, você pode usar o … operador como um operador de propagação que essencialmente converte a matriz em valores. Então, você pode fazer algo assim:

 var myArray = [1,2,3,4,5]; var moreData = [6,7,8,9,10]; myArray = [ ...myArray, ...moreData, ]; 

Embora a syntax seja concisa, não sei como isso funciona internamente e quais são as implicações de desempenho em grandes matrizes.

A function abaixo não tem um problema com o comprimento dos arrays e funciona melhor do que todas as soluções sugeridas:

 function pushArray(list, other) { var len = other.length; var start = list.length; list.length = start + len; for (var i = 0; i < len; i++ , start++) { list[start] = other[i]; } } 

infelizmente, o jspref se recusa a aceitar meus envios, então aqui estão os resultados usando o benchmark.js

  Name | ops/sec | ± % | runs sampled for loop and push | 177506 | 0.92 | 63 Push Apply | 234280 | 0.77 | 66 spread operator | 259725 | 0.40 | 67 set length and for loop | 284223 | 0.41 | 66 

Onde

for loop e push é:

  for (var i = 0, l = source.length; i < l; i++) { target.push(source[i]); } 

Empurre Aplicar:

 target.push.apply(target, source); 

operador de spread:

  target.push(...source); 

e finalmente o 'set length e for loop' é a function acima

Aqui está o caminho do ES6

 var newArray = []; let dataArray1 = [1,2,3,4] let dataArray2 = [5,6,7,8] newArray = [...dataArray1, ...dataArray2] console.log(newArray) 

Pesquisa e Resultados

Para os fatos, um teste de desempenho no jsperf e a verificação de algumas coisas no console são executados. Para a pesquisa, o site irt.org é usado. Abaixo está uma coleção de todas essas fonts juntas e uma function de exemplo na parte inferior.

  ╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
 ║ Método ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Spread ║
 ╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
 ║ mOps / Sec ║179 ║104 ║ 76 ║ 81 ║28 ║
 ╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
 Ar matrizes esparsas ║YES!  ║Só o fatiado ║ não ║ Talvez 2 ║no ║
 ║ mantidas esparsas ║ ║array (1st arg) ║ ║ ║ ║
 ╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
 ║ Suporte ║MSIE 4║MSIE 5.5 ║ MSIE 5.5 ║ MSIE 4 ║Edge 12 ║
 ║ ( fonte ) ║NNav 4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE NNav ║
 ╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
 ║Artes do tipo Arrays║no ║Somente o empurrado ║ SIM!  ║ SIM!  ║ Se tiver ║
 ║ como um array ║ ║array (2nd arg) ║ ║ ║iterator 1 ║
 ╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
 1 Se o object do tipo array não tiver uma propriedade Symbol.iterator , tente
   para espalhá-lo vai lançar uma exceção.
 2 Depende do código.  O seguinte código de exemplo "YES" preserva a dispersão. 
 function mergeCopyTogether(inputOne, inputTwo){ var oneLen = inputOne.length, twoLen = inputTwo.length; var newArr = [], newLen = newArr.length = oneLen + twoLen; for (var i=0, tmp; i !== oneLen; ++i) { tmp = inputOne[i]; if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp; } for (var i=0, tmp; i !== oneLen; ++i) { tmp = inputOne[i]; if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp; } return newArr; } 

Como visto acima, eu diria que o Concat é quase sempre o caminho a percorrer para o desempenho e a capacidade de reter a dispersão de matrizes sobressalentes. Em seguida, para tipos-de-matriz (como DOMNodeLists, como document.body.children ), eu recomendaria usar o loop for, porque ele é o segundo com mais desempenho e o único outro método que mantém matrizes esparsas. Abaixo, veremos rapidamente o que se entende por matrizes esparsas e tipos de matriz para esclarecer a confusão.

O futuro

No início, algumas pessoas podem pensar que isso é um acaso e que os fornecedores de navegadores eventualmente conseguirão otimizar o Array.prototype.push para ser rápido o suficiente para vencer o Array.prototype.concat. ERRADO! Array.prototype.concat será sempre mais rápido (pelo menos em princípio) porque é uma simples cópia e colagem dos dados. Abaixo está um diagrama persuado-visual simplificado do que uma implementação de array de 32 bits pode parecer (por favor, note que as implementações reais são muito mais complicadas)

  Byte ║ Dados aqui
 ═════╬═══════════
 0x00 ║ int nonNumericPropertiesLength = 0 x 0000000000
 0x01 ║ ibid
 0x02 ║ ibid
 0x03 ║ ibid
 0x00 ║ int length = 0x00000001
 0x01 ║ ibid
 0x02 ║ ibid
 0x03 ║ ibid
 0x00 ║ int valueIndex = 0 x 0000000000
 0x01 ║ ibid
 0x02 ║ ibid
 0x03 ║ ibid
 0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
 0x01 ║ ibid
 0x02 ║ ibid
 0x03 ║ ibid
 0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (ou onde quer que esteja na memory)
 0x01 ║ ibid
 0x02 ║ ibid
 0x03 ║ ibid 

Como visto acima, tudo que você precisa fazer para copiar algo assim é quase tão simples quanto copiar o byte para byte. Com o Array.prototype.push.apply, é muito mais do que copiar e colar os dados. O “.apply” tem que verificar cada índice na matriz e convertê-lo em um conjunto de argumentos antes de passá-lo para Array.prototype.push. Então, Array.prototype.push tem que alocar adicionalmente mais memory a cada vez, e (para algumas implementações de navegador) talvez até recalcule alguns dados de busca de posição para dispersão.

Uma maneira alternativa de pensar nisso é isso. A matriz de origem é uma grande pilha de papéis grampeados juntos. A matriz de origem dois também é outra grande pilha de papéis. Seria mais rápido para você

  1. Vá até a loja e compre o papel necessário para uma cópia de cada matriz de origem. Em seguida, coloque cada matriz de pilhas de papel em uma copiadora e grampear as duas cópias juntas.
  2. Vá até a loja, compre papel suficiente para uma única cópia do primeiro array de origem. Em seguida, copie a matriz de origem para o novo papel manualmente, assegurando-se de preencher todos os pontos esparsos em branco. Em seguida, volte para a loja, compre papel suficiente para o segundo array de origem. Em seguida, percorra a segunda matriz de origem e copie-a, assegurando-se de que não haja lacunas em branco na cópia. Em seguida, grampear todos os papéis copiados juntos.

Na analogia acima, a opção # 1 representa Array.prototype.concat, enquanto a # 2 representa Array.prototype.push.apply. Vamos testar isso com um JSperf semelhante, diferindo apenas no fato de que este teste os methods em matrizes esparsas, não em matrizes sólidas. Pode-se encontrar aqui mesmo .

Portanto, descubro que o futuro do desempenho para esse caso de uso específico não está no Array.prototype.push, mas sim no Array.prototype.concat.

Esclarecimentos

Matrizes de reposição

Quando certos membros da matriz estão simplesmente ausentes. Por exemplo:

 // This is just as an example. In actual code, // do not mix different types like this. var mySparseArray = []; mySparseArray[0] = "foo"; mySparseArray[10] = undefined; mySparseArray[11] = {}; mySparseArray[12] = 10; mySparseArray[17] = "bar"; console.log("Length: ", mySparseArray.length); console.log("0 in it: ", 0 in mySparseArray); console.log("arr[0]: ", mySparseArray[0]); console.log("10 in it: ", 10 in mySparseArray); console.log("arr[10] ", mySparseArray[10]); console.log("20 in it: ", 20 in mySparseArray); console.log("arr[20]: ", mySparseArray[20]); 

Nós temos dois arranjos a e b. o código que fez aqui é matriz um valor é empurrado para a matriz b.

 let a = [2, 4, 6, 8, 9, 15] function transform(a) { let b = ['4', '16', '64'] a.forEach(function(e) { b.push(e.toString()); }); return b; } transform(a) [ '4', '16', '64', '2', '4', '6', '8', '9', '15' ] 

em vez da function push () use a function concat para o IE. exemplo,

 var a=a.concat(a,new Array('amin')); 

Isso é um código de trabalho e funciona bem:

 var els = document.getElementsByTagName('input'), i; var invnum = new Array(); var k = els.length; for(i = 0; i < k; i++){invnum.push(new Array(els[i].id,els[i].value))} 

Mais simples:

 var newArray = dataArray1.slice(0);