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.
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
.
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;
}
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;)
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!)
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...]
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.
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
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.
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]
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"]
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());
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);
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]));
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"]
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]