Quel est le moyen le plus efficace d'inverser un tableau en Javascript?

On m'a demandé récemment quel était le moyen le plus efficace d'inverser un tableau en Javascript. Pour le moment, j'ai suggéré d'utiliser une boucle for et de jouer avec le tableau, mais j'ai ensuite réalisé qu'il y avait une méthode native Array.reverse().

Par curiosité, quelqu'un peut-il m'aider à explorer cela en montrant des exemples ou en pointant dans la bonne direction pour que je puisse lire cela? Toutes les suggestions concernant la façon de mesurer les performances seraient également géniales.

53
demandé sur Super Chafouin 2011-03-11 21:38:14

14 réponses

Basé sur cette configuration:

var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var length = array.length;

Array.reverse(); est le premier ou le deuxième plus lent!

Les repères sont ici: http://jsperf.com/js-array-reverse-vs-while-loop/5

Dans tous les navigateurs, les boucles d'échange sont plus rapides. Il existe deux types courants d'algorithmes d'échange (voir Wikipedia ), chacun avec deux variations.

Les deux types d'algorithmes de swap sont le swap temporaire et le swap XOR.

Les deux variations gèrent les calculs d'index différemment. Le la première variation compare l'index gauche actuel et l'index droit, puis décrémente l'index droit du tableau. La deuxième variation compare l'index gauche actuel et la longueur divisée par la moitié, puis recalcule l'index droit pour chaque itération.

Vous pouvez ou ne pouvez pas voir d'énormes différences entre les deux variations. Par exemple, dans Chrome 18, les premières variations du swap temporaire et du swap XOR sont plus de 60% plus lentes que les deuxièmes variations, mais dans Opera 12, les deux les variations du swap temporaire et du swap XOR ont des performances similaires.

D'échange Temporaire:

Première variation:

function temporarySwap(array)
{
    var left = null;
    var right = null;
    var length = array.length;
    for (left = 0, right = length - 1; left < right; left += 1, right -= 1)
    {
        var temporary = array[left];
        array[left] = array[right];
        array[right] = temporary;
    }
    return array;
}

Deuxième variante:

function temporarySwapHalf(array)
{
    var left = null;
    var right = null;
    var length = array.length;
    for (left = 0; left < length / 2; left += 1)
    {
        right = length - 1 - left;
        var temporary = array[left];
        array[left] = array[right];
        array[right] = temporary;
    }
    return array;
}

XOR swap:

Première variation:

function xorSwap(array)
{
    var i = null;
    var r = null;
    var length = array.length;
    for (i = 0, r = length - 1; i < r; i += 1, r -= 1)
    {
        var left = array[i];
        var right = array[r];
        left ^= right;
        right ^= left;
        left ^= right;
        array[i] = left;
        array[r] = right;
    }
    return array;
}

Deuxième variante:

function xorSwapHalf(array)
{
    var i = null;
    var r = null;
    var length = array.length;
    for (i = 0; i < length / 2; i += 1)
    {
        r = length - 1 - i;
        var left = array[i];
        var right = array[r];
        left ^= right;
        right ^= left;
        left ^= right;
        array[i] = left;
        array[r] = right;
    }
    return array;
}

Il existe une autre méthode d'échange appelée affectation de déstructuration: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

Déstructuration affectation:

Première variation:

function destructuringSwap(array)
{
    var left = null;
    var right = null;
    var length = array.length;
    for (left = 0, right = length - 1; left < right; left += 1, right -= 1)
    {
        [array[left], array[right]] = [array[right], array[left]];
    }
    return array;
}

Deuxième variante:

function destructuringSwapHalf(array)
{
    var left = null;
    var right = null;
    var length = array.length;
    for (left = 0; left < length / 2; left += 1)
    {
        right = length - 1 - left;
        [array[left], array[right]] = [array[right], array[left]];
    }
    return array;
}

En ce moment, un algorithme utilisant l'affectation de déstructuration est le plus lent de tous. Il est encore plus lent que Array.reverse();. Cependant, les algorithmes utilisant des affectations de déstructuration et des méthodes Array.reverse(); sont les exemples les plus courts, et ils ont l'air les plus propres. J'espère que leur performance s'améliorera à l'avenir.


Une autre mention est que les navigateurs modernes améliorent leurs performances de matrice push et splice opérations.

Dans Firefox 10, cet algorithme de boucle for utilisant array push et splice rivalise avec les algorithmes de boucle d'échange temporaire et XOR.

for (length -= 2; length > -1; length -= 1)
{
    array.push(array[length]);
    array.splice(length, 1);
}

Cependant, vous devriez probablement rester avec les algorithmes de boucle d'échange jusqu'à ce que beaucoup d'autres navigateurs correspondent ou dépassent leurs performances array push et splice.

67
répondu XP1 2012-02-02 13:27:40

Les méthodes natives sont toujours plus rapides.

Utilisez donc Array.reverse si possible. Sinon, une implémentation qui s'exécute dans O(1) serait la meilleure ;)

Sinon, utilisez simplement quelque chose comme ceci

var reverse = function(arr) {
   var result = [],
       ii = arr.length;
   for (var i = ii - 1;i !== 0;i--) {
       result.push(arr[i]);
   }
   return result;
}

Référence!

Intéressant la boucle est plus rapide si vous utilisez les trois étapes de la construction for au lieu d'une seule.

for(var i = ii - 1; i !== 0;i--) est plus rapide, puis var i = ii - 1;for(;i-- !== 0;)

17
répondu Raynos 2011-03-11 18:59:08

I a ouvert un bogue Firefox sur les performances inverses lentes dans Firefox. Quelqu'un de Mozilla a regardé le benchmark utilisé dans le post accepté, et dit que c'est assez trompeur-dans leur analyse, la méthode native est meilleure en général pour inverser les tableaux. (Comme il se doit!)

10
répondu starwed 2013-03-16 19:35:01

De manière simple, vous pouvez le faire en utilisant map.

let list = [10, 20, 30, 60, 90]
let reversedList = list.map((e, i, a)=> a[(a.length -1) -i]) // [90, 60...]
9
répondu Srinivas Damam 2016-08-11 17:15:17

Puisque personne ne l'a trouvé et pour compléter la liste des moyens d'inverser un tableau...

array.sort(function() {
    return 1;
})

C'est deux fois plus rapide que les deux while-approaches, mais à part ça, horriblement lent.

Http://jsperf.com/js-array-reverse-vs-while-loop/53

5
répondu CoDEmanX 2015-08-28 22:57:30

Les fonctions D'échange sont les plus rapides. Voici une fonction inverse que j'ai écrite qui n'est que légèrement similaire aux fonctions d'échange mentionnées ci-dessus mais qui fonctionne plus rapidement.

function reverse(array) {
  var first = null;
  var last = null;
  var tmp = null;
  var length = array.length;

  for (first = 0, last = length - 1; first < length / 2; first++, last--) {
    tmp = array[first];
    array[first] = array[last];
    array[last] = tmp;
  }
}

, Vous pouvez trouver le benchmarking ici http://jsperf.com/js-array-reverse-vs-while-loop/19

3
répondu Brice Lin 2014-01-22 01:01:15

Voici un exemple java http://www.leepoint.net/notes-java/data/arrays/arrays-ex-reverse.html montrant comment inverser une matrice. Très facile à convertir en javascript.

Je suggère d'utiliser quelque chose qui capture simplement le temps avant l'appel de la fonction, et après l'appel de la fonction. Ce qui prend le moins de temps / cycles d'horloge sera le plus rapide.

2
répondu clamchoda 2011-03-11 18:45:27

Si vous voulez copier une version inversée d'un tableau et conserver l'original tel quel:

a = [0,1,2,3,4,5,6,7,8,9];
b = []
for(i=0;i<a.length;i++){
    b.push(a.slice(a.length-i-1,a.length-i)[0])
}

Sortie de b:

[ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
1
répondu tarikakyol 2014-09-28 18:14:49

Voici un autre exemple pour modifier définitivement le tableau en inversant ses éléments:

var theArray = ['a', 'b', 'c', 'd', 'e', 'f'];

function reverseArrayInPlace(array) {
  for (var i = array.length - 1; i >= 0; i -= 1) {
    array.push(array[i]);
  }
  array.splice(0, array.length / 2);
  return array;
};
reverseArrayInPlace(theArray);
console.log(theArray); // -> ["f", "e", "d", "c", "b", "a"]
1
répondu drjorgepolanco 2015-01-14 00:39:20

Voici quelques astuces que j'ai trouvé. Le crédit va à Codemanx pour la solution originale de

array.sort(function() {
   return 1;
})

Dans Typescript, cela peut être simplifié à une seule ligne

array.sort(() => 1)

var numbers = [1,4,9,13,16];

console.log(numbers.sort(() => 1));

Puisque ce sera L'avenir de JavaScript, j'ai pensé que je partagerais cela.

Voici une autre astuce si votre tableau n'a que 2 éléments

array.push(array.shift());
1
répondu Richard Hamilton 2016-07-12 03:16:41

Une autre suggestion, similaire à ce qui précède, mais en utilisant splice à la place:

var myArray=["one","two","three","four","five","six"];
console.log(myArray);
for(i=0;i<myArray.length;i++){
myArray.splice(i,0,myArray.pop(myArray[myArray.length-1]));
}
console.log(myArray);
1
répondu SlavCo Zute 2017-05-08 12:34:30

C'est le plus efficace et propre façon d'inverser un tableau avec l'opérateur ternaire.

function reverse(arr) {
  return arr.length < 2 ? arr : [arr.pop()].concat(reverse(arr));
}
console.log(reverse([4, 3, 3, 1]));
1
répondu Arslan shakoor 2017-10-24 18:40:49

J'ai trouvé un moyen simple de le faire avec .tranche().inverse ()

var yourArray = ["first", "second", "third", "...", "etc"]
var reverseArray = yourArray.slice().reverse()

console.log(reverseArray)

Vous obtiendrez

["etc", "...", "third", "second", "first"]
0
répondu Kangudie Muanza - Killmonger 2017-12-03 10:11:41

Vous pouvez également utiliser reduceRight qui parcourra chaque valeur du tableau (de droite à gauche)

const myArray = [1, 2, 3, 4, 5]
const reversedArray = myArray.reduceRight((acc, curr) => [...acc, curr], [])
console.log(reversedArray) // [5, 4, 3, 2, 1]
0
répondu Nick D 2018-09-16 19:54:03