web-dev-qa-db-fra.com

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

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

Je veux atteindre les objectifs suivants:

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

Je sais qu'il existe une méthode a.concat(b), mais elle crée un nouveau tableau au lieu d'étendre simplement le premier. J'aimerais un algorithme qui fonctionne efficacement lorsque a est nettement plus grand que b (c'est-à-dire un algorithme qui ne copie pas a).

Remarque: Ceci est ce n'est pas une copie de Comment ajouter quelque chose à un tableau?- le but ici est d'ajouter le contenu entier d'un tableau à l'autre, et le faire "à la place", c'est-à-dire sans copier tous les éléments du tableau étendu.

814
DzinX

La méthode .Push peut prendre plusieurs arguments. Vous pouvez utiliser l'opérateur spread pour transmettre tous les éléments du second tableau sous forme d'arguments à .Push:

>>> a.Push(...b)

Si votre navigateur ne supporte pas ECMAScript 6, vous pouvez utiliser .apply à la place:

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

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

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

Veuillez noter que toutes ces solutions échoueront avec une erreur de débordement de pile si le tableau b est trop long (le problème commence à environ 100 000 éléments, selon le navigateur). Si vous ne pouvez pas garantir que b est suffisamment court, vous devez utiliser une technique standard à base de boucles décrite dans l'autre réponse.

1194
DzinX

Mise à jour 2018: Une meilleure réponse est une plus récente : a.Push(...b). Ne votez plus contre celui-ci, car il n'a jamais vraiment répondu à la question, mais c'était un coup dur de 2015 autour du premier hit-sur-Google :)


Pour ceux qui ont simplement cherché "JavaScript array extend" et 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, car le démarreur de thread ne voulait pas. Mais vous ne vous en souciez peut-être pas (certainement pour la plupart des utilisations, tout ira bien).


Il existe également du sucre ECMAScript 6 de Nice sous la forme de l’opérateur de propagation:

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

(Il copie également.)

222
odinho - Velmont

Vous devriez utiliser une technique basée sur des boucles. Les autres réponses de cette page, basées sur l'utilisation de .apply, peuvent échouer pour les tableaux de grande taille.

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 alors faire ce qui suit:

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

La réponse de DzinX (à l'aide de Push.apply) et d'autres méthodes basées sur .apply échouent lorsque le tableau que nous ajoutons est grand (les tests montrent que, pour moi, le volume est> 150 000 entrées environ dans Chrome et> 500 000 entrées dans Firefox). Vous pouvez voir cette erreur se produire dans this 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 second argument. (MDN a une note sur les dangers liés au dépassement de la taille de la pile d’appels à l’aide de Function.prototype.apply - voir la section intitulée «Fonctions d’application et intégrées».)

Pour une comparaison rapide avec d’autres réponses sur cette page, consultez this jsperf (grâce à EaterOfCode). L'implémentation basée sur les boucles est similaire à la vitesse d'utilisation de Array.Push.apply, mais tend à être un peu plus lente que Array.slice.apply.

Il est intéressant de noter que si le tableau que vous ajoutez est rare, la méthode ci-dessus basée sur forEach peut tirer parti de la rareté et surpasser les méthodes basées sur .apply; Découvrez this jsperf si vous voulez tester cela par vous-même.

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

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

parce que cela produit des résultats erronés! Pourquoi? Étant donné que Array.prototype.forEach fournit trois arguments à la fonction appelée, il s’agit de: (element_value, element_index, source_array). Tous ces éléments seront placés sur votre premier tableau pour chaque itération de forEach si vous utilisez "forEach (this.Push, this)"!

185
jcdude

Je pense que le plus élégant de nos jours est:

arr1.Push(...arr2);

L'article MDN sur l'opérateur de diffusion mentionne cette manière douce de Nice dans ES2015 (ES6):

Une meilleure poussée

Exemple: Push est souvent utilisé pour pousser un tableau à la fin d'un fichier .__ existant. tableau. Dans ES5, cela se fait souvent 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);

Dans 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 (conservez-le sous environ 100 000 articles), car la pile d'appels déborde, comme l'indique la réponse de jcdude.

142
odinho - Velmont

Quelques mots sur apply() en JavaScript pour vous aider à comprendre pourquoi nous l’utilisons:

La méthode apply() appelle une fonction avec une valeur this donnée et arguments fournis sous forme de tableau.

Push attend que list d’éléments s’ajoute au tableau. La méthode apply(), cependant, prend les arguments attendus pour l'appel de fonction sous forme de tableau. Cela nous permet de facilement Push les éléments d'un tableau dans un autre tableau avec la méthode intégrée Push().

Imaginez que vous ayez ces tableaux:

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

et simplement faire 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 ceci:

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

Plus court et meilleur mais pas complètement supporté dans tous les navigateurs pour le moment.

Aussi, si vous voulez déplacer tout du tableau b à a, en vidant b dans le processus, vous pouvez faire ceci:

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

et le résultat sera le suivant:

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

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
Jules Colle

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

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

et l'utiliser comme ça

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

a.append(b)
18

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 laid, il n'est pas plus rapide que Push.apply, du moins pas dans Firefox 3.0.

13
Rafał Dowgird

Cette solution fonctionne pour moi (en utilisant l'opérateur de diffusion d'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);

4

Vous pouvez créer un polyfill pour extend comme indiqué ci-dessous. Cela ajoutera au tableau; in-situ et retourne 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
Mr. Polywhirl

Je peux voir de très bonnes réponses, et tout dépend de la taille de votre tableau, de vos exigences et de votre objectif. Cela peut être fait de différentes manières.

Je suggère d'utiliser une boucle JavaScript pour:

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

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

console.log(a) output sera

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

Ensuite, vous pouvez créer 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)); output sera

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

Utilisez Array.extend au lieu de Array.Push pour plus de 150 000 enregistrements.

if (!Array.prototype.extend) {
  Array.prototype.extend = function(arr) {
    if (!Array.isArray(arr)) {
      return this;
    }

    for (let record of arr) {
      this.Push(record);
    }

    return this;
  };
}
0
Mahdi Pedram

Combiner les réponses ...

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]);
        };
    }  
}
0
zCoder

Une autre solution pour fusionner plus de deux tableaux

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

Ensuite, appelez et imprimez en tant que:

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

La sortie sera: Array [1, 2, 3, 4, 5, 6, 7]

0
user3126309