Pregunta ¿Cómo extender una matriz de JavaScript existente con otra matriz, sin crear una nueva matriz?


Nota: Esto es no es un duplicado de ¿Cómo agregar algo a una matriz? - el objetivo aquí es agregar todo el contenido de una matriz a la otra, y hacerlo "en su lugar", es decir, sin copiar todos los elementos de la matriz extendida.

No parece haber una manera de extender una matriz de JavaScript existente con otra matriz, es decir, emular la de Python. extend método.

Lo que quiero lograr es lo siguiente:

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]

Sé que hay un a.concat(b) método, pero crea una nueva matriz en lugar de simplemente extender la primera. Me gustaría un algoritmo que funcione de manera eficiente cuando a es significativamente más grande que b (es decir, uno que no copia a)


690
2017-09-03 15:27


origen


Respuestas:


los .push método puede tomar múltiples argumentos, por lo que al usar .apply pasar todos los elementos de la segunda matriz como argumentos para .push, puede obtener el resultado que desea:

>>> a.push.apply(a, b)

o tal vez, si crees que es más claro:

>>> Array.prototype.push.apply(a,b)

Si su navegador es compatible con ES6, puede usar operador de propagación, que es más compacto y elegante:

>>> a.push(...b)

Tenga en cuenta que todas estas soluciones fallarán con un error de desbordamiento de pila si la matriz b es demasiado largo (los problemas comienzan en aproximadamente 100,000 elementos, dependiendo del navegador). Si no puedes garantizar eso b es lo suficientemente corto, debe usar una técnica estándar basada en bucle descrita en la otra respuesta.


1071
2017-09-03 15:27



Para aquellos que simplemente buscaron "javascript array extend" y llegaron aquí, pueden usarlo muy bien Array.concat.

var a = [1, 2, 3];
a = a.concat([5, 4, 3]);

Concat devolverá una copia de la nueva matriz, ya que thread starter no lo desea. Pero es posible que no le importe (sin duda para la mayoría de los usos, esto estará bien).


También hay un poco de azúcar ES6 agradable para esto en la forma del operador de propagación:

const a = [1, 2, 3];
const b = [...a, 5, 4, 3];

(también copias)


184
2017-07-20 16:15



Debe usar una técnica basada en bucle. Otras respuestas en esta página que se basan en el uso .apply puede fallar para arreglos grandes

Una implementación bastante escueta basada en bucle es:

Array.prototype.extend = function (other_array) {
    /* you should include a test to check whether other_array really is an array */
    other_array.forEach(function(v) {this.push(v)}, this);    
}

A continuación, puede hacer lo siguiente:

var a = [1,2,3];
var b = [5,4,3];
a.extend(b);

La respuesta de DzinX (usando push.apply) y otros .apply los métodos basados ​​fallan cuando la matriz que estamos agregando es grande (las pruebas muestran que para mí es mayor de 150000 entradas aproximadamente en Chrome, y> 500000 entradas en Firefox). Puede ver que este error ocurre en este jsperf.

Se produce un error porque se excede el tamaño de la pila de llamadas cuando se llama a 'Function.prototype.apply' con una matriz grande como segundo argumento. (El MDN tiene una nota sobre los peligros de exceder el tamaño de la pila de llamadas usando Function.prototype.apply - ver la sección titulada "aplicar y funciones incorporadas")

Para una comparación de velocidad con otras respuestas en esta página echa un vistazo este jsperf (gracias a EaterOfCode). La implementación basada en bucles es similar en velocidad al uso de Array.push.apply, pero tiende a ser un poco más lenta que Array.slice.apply.

Curiosamente, si la matriz que está agregando es escasa, la forEachbasado en el método anterior puede aprovechar la escasez y superar el .apply métodos basados, echa un vistazo este jsperf si quieres probar esto por ti mismo.

Por cierto, ¡no te sientas tentado (como yo lo fui!) A acortar aún más la implementación de forEach para:

Array.prototype.extend = function (array) {
    array.forEach(this.push, this);    
}

porque esto produce resultados de basura! ¿Por qué? Debido a que Array.prototype.forEach proporciona 3 argumentos para la función a la que llama, estos son: (element_value, element_index, source_array). Todos estos se insertarán en su primer array para cada iteración de forEach si usa "forEach (this.push, this)"!


174
2018-06-28 15:16



Siento que el más elegante en estos días es:

arr1.push(...arr2);

los Artículo de MDN sobre el operador de propagación menciona esta agradable manera azucarada en ES2015 (ES6):

Un mejor empuje

Ejemplo: push se usa a menudo para empujar una matriz al final de una existente   formación. En ES5 esto se hace a menudo como:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Append all items from arr2 onto arr1
Array.prototype.push.apply(arr1, arr2);

En ES6 con spread, esto se convierte en:

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

Ten en cuenta que arr2 no puede ser enorme (mantenerlo en alrededor de 100 000 elementos), porque la pila de llamadas se desborda, según la respuesta de jcdude.


127
2018-02-05 11:27



Primero algunas palabras sobre apply() en JavaScript para ayudar a entender por qué lo usamos:

los apply() método llama a una función con un dado this valor, y   argumentos proporcionados como una matriz.

Push espera una lista de elementos para agregar a la matriz. los apply() método, sin embargo, toma los argumentos esperados para la llamada de función como una matriz. Esto nos permite fácilmente push los elementos de una matriz en otra matriz con el built-in push() método.

Imagina que tienes estos arreglos:

var a = [1, 2, 3, 4];
var b = [5, 6, 7];

y simplemente haz esto:

Array.prototype.push.apply(a, b);

El resultado será:

a = [1, 2, 3, 4, 5, 6, 7];

Lo mismo se puede hacer en ES6 usando el operador de difusión ("...") Me gusta esto:

a.push(...b); //a = [1, 2, 3, 4, 5, 6, 7]; 

Más corto y mejor, pero no totalmente compatible con todos los navegadores en este momento.

También si quieres movimiento todo desde array b a avaciando b en el proceso, puedes hacer esto:

while(b.length) {
  a.push(b.shift());
} 

y el resultado será el siguiente:

a = [1, 2, 3, 4, 5, 6, 7];
b = [];

40
2018-05-25 13:05



Si quieres usar jQuery, hay $ .merge ()

Ejemplo:

a = [1, 2];
b = [3, 4, 5];
$.merge(a,b);

Resultado: a = [1, 2, 3, 4, 5]


38
2017-12-24 15:51



me gusta el a.push.apply(a, b) método descrito anteriormente, y si lo desea, siempre puede crear una función de biblioteca como esta:

Array.prototype.append = function(array)
{
    this.push.apply(this, array)
}

y úsalo así

a = [1,2]
b = [3,4]

a.append(b)

18
2018-01-07 10:39



Es posible hacerlo usando splice():

b.unshift(b.length)
b.unshift(a.length)
Array.prototype.splice.apply(a,b) 
b.shift() // restore b
b.shift() // 

Pero a pesar de ser más feo, no es más rápido que push.apply, al menos no en Firefox 3.0. Publicado por completo sake.


13
2017-09-17 12:51



Puedes crear un polyfill para extender como lo hago a continuación. Se agregará a la matriz; en el lugar y regreso en sí mismo, para que pueda encadenar otros métodos.

if (Array.prototype.extend === undefined) {
  Array.prototype.extend = function(other) {
    this.push.apply(this, arguments.length > 1 ? arguments : other);
    return this;
  };
}

function print() {
  document.body.innerHTML += [].map.call(arguments, function(item) {
    return typeof item === 'object' ? JSON.stringify(item) : item;
  }).join(' ') + '\n';
}
document.body.innerHTML = '';

var a = [1, 2, 3];
var b = [4, 5, 6];

print('Concat');
print('(1)', a.concat(b));
print('(2)', a.concat(b));
print('(3)', a.concat(4, 5, 6));

print('\nExtend');
print('(1)', a.extend(b));
print('(2)', a.extend(b));
print('(3)', a.extend(4, 5, 6));
body {
  font-family: monospace;
  white-space: pre;
}


2
2017-09-17 13:02



Puedo ver respuestas muy buenas, y todo depende del tamaño de su matriz, su requisito y meta. Se puede hacer de diferentes maneras.

Sugiero usar JavaScript For Loop:

var a = [1, 2];
var b = [3, 4, 5];

for (i = 0; i < b.length; i++) {
    a.push(b[i]);
}

console.log(a) salida será

Array [ 1, 2, 3, 4, 5 ]

Entonces puedes hacer tu propia función:

function extendArray(a, b){
    for (i = 0; i < b.length; i++) {
        a.push(b[i]);
    }
    return a;
}

console.log(extendArray(a, b)); salida será

Array [ 1, 2, 3, 4, 5 ]

2
2017-09-17 14:24



Combinando las respuestas ...

Array.prototype.extend = function(array) {
    if (array.length < 150000) {
        this.push.apply(this, array)
    } else {
        for (var i = 0, len = array.length; i < len; ++i) {
            this.push(array[i]);
        };
    }  
}

1
2017-09-11 10:10