105 votes

Créer une copie d'un tableau multidimensionnel, et non une référence - JavaScript

On parle aussi de "copie profonde", sur laquelle j'ai trouvé quelques articles. Le plus proche semble être celui-ci mais c'est pour jQuery - j'essaie de faire ça sans bibliothèque.

J'ai également vu, à deux endroits, qu'il est possible de faire quelque chose comme :

arr2 = JSON.decode(JSON.encode(arr1));

Mais c'est apparemment inefficace. Il est également possible de boucler et de copier chaque valeur individuellement, et de récurer tous les tableaux. Cela semble également fastidieux et inefficace.

Quelle est donc la méthode la plus efficace et la moins coûteuse pour copier un tableau multidimensionnel JavaScript ? [[a],[b],[c]] ? Je suis tout à fait satisfait d'une méthode "non-IE" si nécessaire.

Merci !

126voto

I Hate Lazy Points 18168

Puisqu'il semble que vous traitiez un tableau de tableaux à un niveau de profondeur inconnu, mais que vous n'avez besoin de les traiter qu'à un seul niveau de profondeur à un moment donné, il sera simple et rapide d'utiliser la méthode suivante .slice() .

var newArray = [];

for (var i = 0; i < currentArray.length; i++)
    newArray[i] = currentArray[i].slice();

Ou en utilisant .map() au lieu de la for boucle :

var newArray = currentArray.map(function(arr) {
    return arr.slice();
});

Cela itère donc le tableau actuel, et construit un nouveau tableau de copies superficielles des tableaux imbriqués. Ensuite, lorsque vous passez au niveau de profondeur suivant, vous faites la même chose.

Bien sûr, s'il y a un mélange de tableaux et d'autres données, vous voudrez tester ce qu'il en est avant de trancher.

27voto

Ian Points 23712

Je ne suis pas sûr que ce soit beaucoup mieux JSON.stringify y JSON.parse que encode y decode mais vous pouvez essayer :

JSON.parse(JSON.stringify(array));

Autre chose que j'ai trouvé (même si je le modifierais un peu) :

http://www.xenoveritas.org/blog/xeno/the-correct-way-to-clone-javascript-arrays

function deepCopy(obj) {
  if (typeof obj == 'object') {
    if (isArray(obj)) {
      var l = obj.length;
      var r = new Array(l);
      for (var i = 0; i < l; i++) {
        r[i] = deepCopy(obj[i]);
      }
      return r;
    } else {
      var r = {};
      r.prototype = obj.prototype;
      for (var k in obj) {
        r[k] = deepCopy(obj[k]);
      }
      return r;
    }
  }
  return obj;
}

6voto

Bergi Points 104242

Comme vous avez demandé des performances, je suppose que vous opteriez également pour une solution non générique. Pour copier un tableau multidimensionnel avec un nombre connu de niveaux, vous devriez opter pour la solution la plus simple, des boucles for imbriquées. Pour votre tableau à deux dimensions, cela ressemblerait simplement à ceci :

var len = arr.length,
    copy = new Array(len); // boost in Safari
for (var i=0; i<len; ++i)
    copy[i] = arr[i].slice(0);

Pour étendre à des tableaux de plus grande dimension, utilisez la récursion ou des boucles for imbriquées !

Le natif slice méthode est plus efficace qu'une boucle for personnalisée, mais elle ne crée pas de copies profondes, de sorte que nous ne pouvons l'utiliser qu'au niveau le plus bas.

3voto

Jeff Points 2524

Tout algorithme récursif qui ne visite pas deux fois le même nœud sera à peu près aussi efficace que ce que l'on peut obtenir avec javascript (au moins dans un navigateur) - dans certaines situations, dans d'autres langages, on peut s'en sortir en copiant des morceaux de mémoire, mais javascript n'a évidemment pas cette capacité.

Je vous suggère de trouver quelqu'un qui déjà fait et en utilisant leur mise en œuvre pour s'assurer que tout est correct - il ne doit être défini qu'une seule fois.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X