length - Come estendere un array JavaScript esistente con un altro array, senza creare un nuovo array




js array (10)

È possibile creare un polyfill per estendere come ho di seguito. Si aggiungerà all'array; sul posto e restituisce se stesso, in modo da poter concatenare altri metodi.

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;
}

Non sembra essere un modo per estendere un array JavaScript esistente con un altro array, ovvero per emulare il metodo di extend di Python.

Voglio raggiungere il seguente:

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

So che esiste un a.concat(b) , ma crea una nuova matrice invece di estendere semplicemente la prima. Mi piacerebbe un algoritmo che funzioni efficientemente quando a è significativamente più grande di b (cioè uno che non copia a ).

Nota: questo non è un duplicato di Come aggiungere qualcosa a un array? - l'obiettivo qui è quello di aggiungere l'intero contenuto di un array all'altro e di farlo "in posizione", cioè senza copiare tutti gli elementi dell'array esteso.


È possibile farlo usando splice() :

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

Ma nonostante sia più brutto non è più veloce di push.apply , almeno non in Firefox 3.0.


Dovresti usare una tecnica basata su loop. Altre risposte su questa pagina basate sull'uso di .apply possono fallire per array di grandi dimensioni.

Un'implementazione basata su loop abbastanza concisa è:

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);
}

È quindi possibile effettuare le seguenti operazioni:

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

La risposta di DzinX (usando push.apply) e altri metodi basati su .apply falliscono quando l'array che stiamo accodando è di grandi dimensioni (i test mostrano che per me grande è> 150.000 voci circa in Chrome e> 500.000 voci in Firefox). Puoi vedere questo errore che si verifica in questo jsperf .

Si verifica un errore perché la dimensione dello stack delle chiamate viene superata quando "Function.prototype.apply" viene chiamato con un array di grandi dimensioni come secondo argomento. (MDN ha una nota sui pericoli del superamento delle dimensioni dello stack di chiamate usando .apply - consulta la sezione intitolata "applica e funzioni integrate".)

Per un confronto di velocità con altre risposte in questa pagina, controlla questo jsperf (grazie a EaterOfCode). L'implementazione basata su loop è simile nella velocità all'utilizzo di Array.push.apply , ma tende ad essere un po 'più lenta di Array.slice.apply .

È interessante notare che se la matrice che si sta aggiungendo è sparsa, il metodo basato su forEach sopra può trarre vantaggio dalla scarsità e sovraperformare i metodi basati .apply ; controlla questo jsperf se vuoi testarlo da solo.

A proposito, non essere tentato (come lo ero io!) Di accorciare ulteriormente l'implementazione forEach per:

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

perché questo produce risultati spazzatura! Perché? Perché Array.prototype.forEach fornisce tre argomenti alla funzione che chiama, ovvero: (elemento_valore, elemento_indice, matrice_origine). Tutti questi verranno spinti sul primo array per ogni iterazione di forEach se si utilizza "forEach (this.push, this)"!


Il metodo .push può accettare più argomenti, quindi usando .apply per passare tutti gli elementi del secondo array come argomenti a .push , puoi ottenere il risultato desiderato:

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

O forse, se pensi che sia più chiaro:

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

Se il tuo browser supporta ECMAScript 6, puoi usare l' operatore di spread , che è più compatto ed elegante:

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

Si noti che tutte queste soluzioni falliranno con un errore di overflow dello stack se l'array b è troppo lungo (i problemi iniziano a circa 100.000 elementi, a seconda del browser). Se non è possibile garantire che b sia abbastanza breve, è necessario utilizzare una tecnica basata su loop standard descritta nell'altra risposta.


Mi piace il a.push.apply(a, b) descritto sopra e, se lo desideri, puoi sempre creare una funzione di libreria come questa:

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

e usalo in questo modo

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

a.append(b)

Mi sento il più elegante di questi tempi è:

arr1.push(...arr2);

L' articolo MDN sull'operatore di diffusione menziona questo simpatico modo zuccherino in ES2015 (ES6):

Una spinta migliore

Esempio: push viene spesso utilizzato per spingere un array alla fine di un array esistente. In ES5 questo è spesso fatto come:

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

In ES6 con diffusione questo diventa:

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

Si noti che arr2 non può essere enorme (mantenetelo sotto circa 100.000 voci), perché lo stack delle chiamate trabocca, come da risposta di jcdude.


Questa soluzione funziona per me (utilizzando l'operatore di diffusione di ECMAScript 6):

let array = ['my', 'solution', 'works'];
let newArray = [];
let newArray2 = [];
newArray.push(...array); // Adding to same array
newArray2.push([...array]); // Adding as child/leaf/sub-array
console.log(newArray);
console.log(newArray2);


Riesco a vedere risposte molto belle, e tutto dipende dalle dimensioni della tua matrice, dalle tue esigenze e dal tuo obiettivo. Può essere fatto in diversi modi.

Suggerisco di utilizzare un ciclo JavaScript per:

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

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

console.log(a) output di console.log(a) sarà

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

Quindi puoi creare la tua funzione:

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

console.log(extendArray(a, b)); l'output sarà

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

Un'altra soluzione per unire più di due array

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

// Merge the contents of multiple arrays together into the first array
var mergeArrays = function() {
 var i, len = arguments.length;
 if (len > 1) {
  for (i = 1; i < len; i++) {
    arguments[0].push.apply(arguments[0], arguments[i]);
  }
 }
};

Quindi chiama e stampa come:

mergeArrays(a, b, c);
console.log(a)

L'output sarà: Array [1, 2, 3, 4, 5, 6, 7]


Aggiornamento 2018 : Una risposta migliore è una delle mie più recenti : a.push(...b) . Non rinunciare più a questo, dato che non ha mai risposto alla domanda, ma è stato un trucco del 2015 in giro per la prima volta su Google :)

Per coloro che hanno semplicemente cercato "estensione di array JavaScript" e sono arrivati ​​qui, puoi usare molto bene Array.concat .

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

Concat restituirà una copia del nuovo array, poiché l'iniziatore di thread non lo desiderava. Ma potrebbe non interessarti (sicuramente per la maggior parte degli usi questo andrà bene).

C'è anche un bel zucchero ECMAScript 6 per questo sotto forma di operatore di spread:

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

(Copia anche).





concatenation