Question Comment étendre un tableau JavaScript existant avec un autre tableau, sans créer un nouveau tableau?


Remarque: C'est pas un duplicata de Comment ajouter quelque chose à un tableau? - le but ici est d'ajouter tout le contenu d'un tableau à l'autre, et de le faire "en place", c'est-à-dire sans copier tous les éléments du tableau étendu.

Il ne semble pas y avoir un moyen d'étendre un tableau JavaScript existant avec un autre tableau, c'est-à-dire pour émuler Python extend méthode.

Ce que je veux réaliser est le suivant:

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

Je sais qu'il y a un a.concat(b) méthode, mais il crée un nouveau tableau au lieu de simplement étendre le premier. Je voudrais un algorithme qui fonctionne efficacement quand a est significativement plus grand que b (c'est-à-dire celui qui ne copie pas a).


690
2017-09-03 15:27


origine


Réponses:


le .push méthode peut prendre plusieurs arguments, donc en utilisant .apply passer tous les éléments du second tableau comme arguments .push, vous pouvez obtenir le résultat que vous voulez:

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

ou peut-être, si vous pensez que c'est plus clair:

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

Si votre navigateur prend en charge ES6, vous pouvez utiliser le opérateur de propagation, qui est plus compact et élégant:

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

S'il vous plaît noter que toutes ces solutions échoueront avec une erreur de débordement de pile si tableau b est trop long (les problèmes commencent à environ 100 000 éléments, selon le navigateur). Si vous ne pouvez pas garantir que b est assez court, vous devez utiliser une technique basée sur une boucle standard décrite dans l'autre réponse.


1071
2017-09-03 15:27



Pour ceux qui ont simplement cherché "javascript array extend" et qui sont arrivés ici, vous pouvez très bien utiliser Array.concat.

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

Concat retournera une copie du nouveau tableau, comme le démarreur de thread ne voulait pas. Mais vous pourriez ne pas s'en soucier (certainement pour la plupart des utilisations cela ira bien).


Il y a aussi du bon sucre ES6 pour cela sous la forme de l'opérateur spread:

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

(aussi des copies)


184
2017-07-20 16:15



Vous devriez utiliser une technique basée sur une boucle. D'autres réponses sur cette page qui sont basées sur l'utilisation .apply peut échouer pour les grandes baies.

Une implémentation basée sur une boucle assez laconique est:

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

Vous pouvez ensuite faire ce qui suit:

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

La réponse de DzinX (en utilisant push.apply) et autres .apply les méthodes basées échouent lorsque le tableau que nous ajoutons est grand (les tests montrent que pour moi, il y a environ 150000 entrées environ dans Chrome, et> 500000 entrées dans Firefox). Vous pouvez voir cette erreur se produire dans ce jsperf.

Une erreur se produit car la taille de la pile d'appels est dépassée lorsque 'Function.prototype.apply' est appelé avec un grand tableau comme deuxième argument. (Le MDN a une note sur les dangers de dépasser la taille de la pile d'appel en utilisant Function.prototype.apply - voir la section intitulée "fonctions applicables et intégrées")

Pour une comparaison de vitesse avec d'autres réponses sur cette page consultez ce jsperf (merci à EaterOfCode). L'implémentation basée sur une boucle est similaire en vitesse à l'utilisation de Array.push.apply, mais a tendance à être un peu plus lente que Array.slice.apply.

Fait intéressant, si le tableau que vous ajoutez est clairsemé, le forEachméthode basée ci-dessus peut tirer parti de la parcimonie et surpasser la .apply méthodes basées, consultez ce jsperf si vous voulez tester cela par vous-même.

En passant, ne soyez pas tenté (comme je l'étais!) De raccourcir davantage l'implémentation forEach pour:

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

parce que cela produit des résultats d'ordures! Pourquoi? Parce que Array.prototype.forEach fournit 3 arguments à la fonction qu'il appelle - ce sont: (élément_valeur, élément_élément, source_array). Tout cela sera poussé sur votre premier tableau pour chaque itération de forEach si vous utilisez "forEach (this.push, this)"!


174
2018-06-28 15:16



Je me sens le plus élégant de nos jours est:

arr1.push(...arr2);

le Article de MDN sur l'opérateur de propagation mentionne cette belle manière sucrée en ES2015 (ES6):

Une meilleure poussée

Exemple: push est souvent utilisé pour pousser un tableau à la fin d'un existant   tableau. Dans ES5, ceci est souvent fait comme suit:

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 avec propagation, cela devient:

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

Notez que arr2 ne peut pas être énorme (garder moins de 100 000 éléments), car la pile d'appels déborde, selon la réponse de jcdude.


127
2018-02-05 11:27



D'abord quelques mots sur apply() en JavaScript pour aider à comprendre pourquoi nous l'utilisons:

le apply() méthode appelle une fonction avec un donné this valeur, et   arguments fournis sous la forme d'un tableau.

Push attend un liste d'éléments à ajouter au tableau. le apply() Toutefois, la méthode prend les arguments attendus pour l'appel de la fonction en tant que tableau. Cela nous permet de facilement push les éléments d'un tableau dans un autre tableau avec le builtin push() méthode.

Imaginez que vous avez ces tableaux:

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

et faites simplement ceci:

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

Le résultat sera:

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

La même chose peut être faite dans ES6 en utilisant l'opérateur spread ("...") comme ça:

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

Plus court et mieux mais pas complètement pris en charge dans tous les navigateurs en ce moment.

Aussi, si vous voulez bouge toi tout de tableau b à a, vidage b dans le processus, vous pouvez le faire:

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

et le résultat sera le suivant:

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

40
2018-05-25 13:05



Si vous voulez utiliser jQuery, il y a $ .merge ()

Exemple:

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

Résultat: a = [1, 2, 3, 4, 5]


38
2017-12-24 15:51



J'aime le a.push.apply(a, b) méthode décrite ci-dessus, et si vous voulez, vous pouvez toujours créer une fonction de bibliothèque comme ceci:

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

et l'utilise comme ça

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

a.append(b)

18
2018-01-07 10:39



Il est possible de le faire en utilisant splice():

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

Mais en dépit d'être plus laide, il n'est pas plus rapide que push.apply, au moins pas dans Firefox 3.0. Publié pour l'intégralité.


13
2017-09-17 12:51



Vous pouvez créer un polyfill pour étendre comme je l'ai ci-dessous. Il va ajouter au tableau; en place et revenir lui-même, de sorte que vous pouvez enchaîner d'autres méthodes.

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



Je peux voir de très bonnes réponses, et tout dépend de la taille de votre tableau, de vos besoins et de vos objectifs. Cela peut être fait de différentes façons.

Je suggère d'utiliser 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) la sortie sera

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

Ensuite, vous pouvez faire votre propre fonction:

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

console.log(extendArray(a, b)); la sortie sera

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

2
2017-09-17 14:24