Copier les éléments du tableau dans un autre tableau


918

J'ai un tableau JavaScript dataArrayque je veux insérer dans un nouveau tableau newArray. Sauf que je ne veux newArray[0]pas l'être dataArray. Je veux insérer tous les éléments dans le nouveau tableau:

var newArray = [];

newArray.pushValues(dataArray1);
newArray.pushValues(dataArray2);
// ...

ou encore mieux:

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

Alors maintenant, le nouveau tableau contient toutes les valeurs des tableaux de données individuels. Y a-t-il des raccourcis comme pushValuesdisponibles, donc je n'ai pas à répéter sur chaque individu dataArray, en ajoutant les éléments un par un?



Cela devrait être la réponse davidwalsh.name/combining-js-arrays
starikovs

Est-ce que cela répond à votre question? Comment fusionner deux tableaux en JavaScript et
supprimer

Réponses:


1249

Utilisez la fonction concat , comme ceci:

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

La valeur de newArraysera [1, 2, 3, 4]( arrayAet arrayBrestera inchangée; concatcrée et renvoie un nouveau tableau pour le résultat).



16
Je suis d'accord que l'exécution performante est très agréable. MAIS n'est-ce pas concat exactement dans ce but pour concaténer des tableaux? Cela devrait donc être standard . Ou y a-t-il d'autres meilleures choses à faire avec concat? Et cela pourrait être lent uniquement en raison d'une mauvaise implémentation du moteur JS du navigateur ou partout où vous l'utilisez? Il pourrait être réparé un jour. Je choisirais la maintenabilité du code plutôt que les optimisations de vitesse hacky. Hmm ....
Bitterblue

3
De plus, je viens de comparer la situation: concat vs push.apply. Google Chrome: rapide (concat = gagnant) Opera,: rapide (concat = gagnant) IE,: plus lent (concat = gagnant) Firefox,: lent (push.apply = gagnant, mais 10 fois plus lent que le concat de Chrome) ... parler de mauvaise implémentation du moteur JS .
Bitterblue

15
Comment concaténer deux tableaux est-il la réponse acceptée pour savoir comment les pousser l' un dans l'autre?! Ce sont deux opérations différentes.
kaqqao

@kaqqao car pushne pas aplatir un tableau de valeurs. concatréalise ce que la question requiert.
WiseGuyEh

644

À condition que vos tableaux ne soient pas énormes (voir la mise en garde ci-dessous), vous pouvez utiliser la push()méthode du tableau auquel vous souhaitez ajouter des valeurs. push()peut prendre plusieurs paramètres afin que vous puissiez utiliser sa apply()méthode pour passer le tableau de valeurs à pousser comme une liste de paramètres de fonction. Cela a l'avantage par rapport à l' concat()ajout d'éléments au tableau en place plutôt que de créer un nouveau tableau.

Cependant, il semble que pour les grands tableaux (de l'ordre de 100 000 membres ou plus), cette astuce peut échouer . Pour de tels tableaux, l'utilisation d'une boucle est une meilleure approche. Voir https://stackoverflow.com/a/17368101/96100 pour plus de détails.

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

Vous voudrez peut-être généraliser cela en une fonction:

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

... ou ajoutez-le au Arrayprototype de:

Array.prototype.pushArray = function(arr) {
    this.push.apply(this, arr);
};

var newArray = [];
newArray.pushArray(dataArray1);
newArray.pushArray(dataArray2);

... ou émuler la push()méthode d' origine en autorisant plusieurs paramètres en utilisant le fait que concat(), comme push(), permet plusieurs paramètres:

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

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

Voici une version en boucle du dernier exemple, adaptée aux grands tableaux et à tous les principaux navigateurs, y compris 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]);
    }
};

9
note: newArray.push.apply(newArray, dataArray1);donne la même chose queArray.prototype.push.applay(newArray,dataArra1);

Est-ce compatible avec les anciens navigateurs?
Damien Ó Ceallaigh


1
@ DamienÓCeallaigh: Oui. Tout cela est compatible avec les navigateurs remontant à IE 6 et même plus tôt.
Tim Down le

C'est la quintessence des mauvaises pratiques de programmation. Array.prototype.concatn'est pas mauvais, il est plutôt simplement mal compris et parfois mal utilisé. Dans ces circonstances, il est seulement mal compris, mais pas mal utilisé.
Jack Giffin

446

Je vais ajouter une autre réponse "à l'épreuve du temps"

Dans ECMAScript 6, vous pouvez utiliser la syntaxe Spread :

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

console.log(arr1)

La syntaxe de propagation n'est pas encore incluse dans tous les principaux navigateurs. Pour la compatibilité actuelle, consultez ce tableau de compatibilité (continuellement mis à jour) .

Vous pouvez cependant utiliser la syntaxe étendue avec Babel.js .

Éditer:

Voir la réponse de Jack Giffin ci-dessous pour plus de commentaires sur les performances. Il semble que le concat est encore meilleur et plus rapide que l'opérateur de propagation.


7
Vous pouvez également utiliser l'opérateur d'étalement si vous utilisez TypeScript. Si vous ciblez ES5, il sera compilé en newArray.apply(newArray, dataArray1).
AJ Richardson

5
Remarque: si vous avez besoin du résultat dans un troisième tableau (donc ne modifiant pas arr1, comme la question initiale semblait exiger), vous pouvez faire newArray = [... arr1, ... arr2]
dim

Oh je ne le savais pas. Merci. J'ai ajouté un commentaire d'édition.
Karel Bílek

Similaire à la façon dont concat fonctionnerait alors, avec le bonus d'être persistant (en mutant le tableau d'origine).
Rob

@robertmylne L'opérateur d'étalement ne modifie évidemment pas le tableau d'origine, créant plutôt une nouvelle copie de tous les contenus des tableaux analysés.
Jack Giffin

145

Trouvé une manière élégante de 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 vous pouvez utiliser la spread operatorfonctionnalité d'ES6:

let fruits = [ 'apple', 'banana'];
const moreFruits = [ 'orange', 'plum' ];

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]

1
Ce n'est pas ce que la question demandait. La question demande un moyen de créer un nouveau tableau à chaque fois, pas de modifier un ancien tableau.
Jack Giffin

13
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)

Est-ce que cela résout votre problème?


13

Ce qui me semble le plus simple:

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

Comme "push" prend un nombre variable d'arguments, vous pouvez utiliser la applyméthode de la pushfonction pour pousser tous les éléments d'un autre tableau. Il construit un appel à pousser en utilisant son premier argument ("newArray" ici) comme "this" et les éléments du tableau comme arguments restants.

Dans slicela première instruction obtient une copie du premier tableau, donc vous ne le modifiez pas.

Mise à jour Si vous utilisez une version de javascript avec une tranche disponible, vous pouvez simplifierpush expression pour:

newArray.push(...dataArray2)

1
Est également mentionné ici à MDN comme un exemple de "Fusion de deux tableaux"
Wilt

12

La fonction ci-dessous n'a pas de problème avec la longueur des tableaux et fonctionne mieux que toutes les solutions suggérées:

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

malheureusement, jspref refuse d'accepter mes soumissions, alors voici les résultats en utilisant 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

pour boucle et push est:

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

Appuyez sur Appliquer:

target.push.apply(target, source);

opérateur de spread:

    target.push(...source);

et enfin la «longueur définie et pour la boucle» est la fonction ci-dessus


Cette question cherche un moyen de créer un nouveau tableau à chaque fois, pas de modifier un tableau existant.
Jack Giffin

10

𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀

Pour les faits, un test de performance sur jsperf et une vérification de certaines choses dans la console sont effectués. Pour la recherche, le site Internet irt.org est utilisé. Vous trouverez ci-dessous une collection de toutes ces sources ainsi qu'un exemple de fonction en bas.

╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║ Méthode ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Spread ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / sec ║179 ║104 ║ 76 ║ 81 ║28 ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Tableaux clairsemés ║OUI! ║Seulement les tranches ║ non ║ Peut-être 2   ║non ║
║ clairsemé ║ rayarray (1er argument) ║ ║ ║ ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Prise en charge ║MSIE 4║MSIE 5.5 IE MSIE 5.5 IE MSIE 4 ║Edge 12 ║
║ ( source ) ║NNav 4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE  NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║Activités de type tableau║non ║Seulement le poussé ║ OUI! ║ OUI! HaveSi have
║comme un tableau ║ rayarray (2nd arg) ║ ║ ║iterator 1   ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1 Si l'objet de type tableau n'a pas de propriété Symbol.iterator , essayez
  pour le diffuser, il lèvera une exception.
2 Dépend du code. L'exemple de code suivant "OUI" préserve la parcimonie.
function mergeCopyTogether(inputOne, inputTwo){
   var oneLen = inputOne.length, twoLen = inputTwo.length;
   var newArr = [], newLen = newArr.length = oneLen + twoLen;
   for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
        tmp = inputOne[i];
        if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
    }
    for (var two=0; i !== newLen; ++i, ++two) {
        tmp = inputTwo[two];
        if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
    }
    return newArr;
}

Comme vu ci-dessus, je dirais que Concat est presque toujours la voie à suivre pour les performances et la capacité à conserver la rareté des tableaux de rechange. Ensuite, pour les tableaux comme (comme DOMNodeLists comme document.body.children), je recommanderais d'utiliser la boucle for car c'est à la fois la 2e méthode la plus performante et la seule autre méthode qui conserve des tableaux clairsemés. Ci-dessous, nous passerons rapidement en revue ce que l'on entend par tableaux clairsemés et tableaux similaires pour dissiper la confusion.

𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲

Au début, certaines personnes peuvent penser qu'il s'agit d'un hasard et que les fournisseurs de navigateurs finiront par optimiser l'optimisation d'Array.prototype.push pour être suffisamment rapide pour battre Array.prototype.concat. FAUX! Array.prototype.concat sera toujours plus rapide (en principe au moins) car il s'agit d'un simple copier-coller sur les données. Vous trouverez ci-dessous un diagramme persuado-visuel simplifié de ce à quoi pourrait ressembler une implémentation de tableau 32 bits (veuillez noter que les implémentations réelles sont BEAUCOUP plus compliquées)

Octet ║ Données ici
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 length longueur int = 0x00000001
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueIndex = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (ou partout où il est en mémoire)
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid

Comme vu ci-dessus, tout ce que vous devez faire pour copier quelque chose comme ça est presque aussi simple que de le copier octet par octet. Avec Array.prototype.push.apply, c'est bien plus qu'un simple copier-coller sur les données. Le ".apply" doit vérifier chaque index du tableau et le convertir en un ensemble d'arguments avant de le passer à Array.prototype.push. Ensuite, Array.prototype.push doit en outre allouer plus de mémoire à chaque fois, et (pour certaines implémentations de navigateur), peut-être même recalculer certaines données de recherche de position pour la rareté.

Une autre façon d'y penser est la suivante. Le tableau source est une grande pile de papiers agrafés ensemble. Le tableau source deux est également une autre grande pile de papiers. Serait-il plus rapide pour vous de

  1. Allez au magasin, achetez suffisamment de papier pour une copie de chaque tableau source. Ensuite, placez chaque pile source de papier dans une photocopieuse et agrafez les deux copies résultantes ensemble.
  2. Allez au magasin, achetez suffisamment de papier pour une seule copie de la première matrice source. Ensuite, copiez le tableau source sur le nouveau papier à la main, en veillant à remplir tous les points clairsemés vides. Ensuite, retournez au magasin, achetez suffisamment de papier pour la deuxième matrice source. Ensuite, parcourez le deuxième tableau source et copiez-le tout en vous assurant qu'il n'y a pas d'espace vide dans la copie. Ensuite, agrafez tous les papiers copiés ensemble.

Dans l'analogie ci-dessus, l'option # 1 représente Array.prototype.concat tandis que # 2 représente Array.prototype.push.apply. Essayons cela avec un JSperf similaire qui ne diffère que par le fait que celui-ci teste les méthodes sur des tableaux clairsemés, pas des tableaux solides. On peut le trouver ici .

Par conséquent, je me repose sur le fait que l'avenir des performances pour ce cas d'utilisation particulier ne réside pas dans Array.prototype.push, mais plutôt dans Array.prototype.concat.

𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀

𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀

Lorsque certains membres du tableau sont simplement manquants. Par exemple:

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

Alternativement, javascript vous permet d'initialiser facilement des tableaux de rechange.

var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];

𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀

Un tableau-comme est un objet qui a au moins une lengthpropriété, mais n'a pas été initialisé avec new Arrayou []; Par exemple, les objets ci-dessous sont classés comme des tableaux.

{0: "foo", 1: "bar", longueur: 2}
document.body.children
nouveau Uint8Array (3)
  • Cela ressemble à un tableau car bien qu'il s'agisse d'un tableau (n) (typé), le contraindre à un tableau change le constructeur.
(fonction () {retourner les arguments}) ()

Observez ce qui se passe en utilisant une méthode qui contraint les tableaux comme des tableaux comme des tranches.

  • REMARQUE: il est incorrect d'appeler slice sur les arguments de fonction en raison des performances.

Observez ce qui se passe en utilisant une méthode qui ne contraint pas les tableaux comme dans des tableaux comme concat.


9

Avec JavaScript ES6, vous pouvez utiliser l'opérateur ... comme opérateur d'étalement qui convertira essentiellement le tableau en valeurs. Ensuite, vous pouvez faire quelque chose comme ceci:

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

const newArray = [
  ...myArray,
  ...moreData,
];

Bien que la syntaxe soit concise, je ne sais pas comment cela fonctionne en interne et quelles sont les implications en termes de performances sur les grands tableaux.


2
Si vous regardez comment babel le convertit , vous verrez que cela ne devrait pas être plus lent que d'utiliser la Array.push.applytechnique.
emil.c

1
@JackGiffin Je faisais juste référence à ce que Ryan a mentionné qu'il ne sait pas comment cela fonctionne en interne et quelles sont les implications en termes de performances, je ne proposais pas réellement cette approche. En tout cas, vous avez fait du très bon travail sur votre réponse, belle recherche, c'est toujours bon de connaître de tels détails.
emil.c

9

Voici la manière ES6

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

La méthode ci-dessus est bonne pour la plupart des cas et les cas ne le sont pas s'il vous plaît concat, comme vous avez des centaines de milliers d'articles dans des tableaux.

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


8

Il existe un certain nombre de réponses concernant Array.prototype.push.apply . Voici un exemple clair:

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]

Si vous avez la syntaxe ES6:

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


4

Si vous souhaitez modifier le tableau d'origine, vous pouvez étaler et pousser:

var source = [1, 2, 3];
var range = [5, 6, 7];
var length = source.push(...range);

console.log(source); // [ 1, 2, 3, 5, 6, 7 ]
console.log(length); // 6

Si vous voulez vous assurer que seuls les éléments du même type entrent dans le sourcetableau (sans mélanger les nombres et les chaînes par exemple), utilisez alors TypeScript.

/**
 * Adds the items of the specified range array to the end of the source array.
 * Use this function to make sure only items of the same type go in the source array.
 */
function addRange<T>(source: T[], range: T[]) {
    source.push(...range);
}

2

Nous avons deux tableaux a et b. le code qui a fait ici est tableau une valeur est poussée dans le tableau 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' ]

1
Veuillez ne pas simplement poster le code comme réponse. Expliquez ce que fait le code et comment il résout le problème.
Patrick Hund

0

Essaye ça:

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayB.reduce((pre, cur) => [...pre, ...cur], arrayA);
console.log(newArray)

-2

au lieu de la fonction push (), utilisez la fonction concat pour IE. exemple,

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

1
les deux sont très compatibles avec IE
Jack Giffin

-3

Ceci est un code de travail et il fonctionne très bien:

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))}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.