在Javascript中反转数组最有效的方法是什么?

时间:2022-09-23 17:13:23

I was asked recently what was the most efficient way to reverse an array in Javascript. At the moment, I suggested using a for loop and fiddling with the array but then realized there is a native Array.reverse() method.

最近有人问我,在Javascript中反转数组最有效的方式是什么?目前,我建议使用for循环和摆弄数组,但随后发现有一个本机Array.reverse()方法。

For curiosity's sake, can anyone help me explore this by showing examples or pointing in the right direction so I can read into this? Any suggestions regarding how to measure performance would be awesome too.

看在好奇的份上,谁能帮助我通过展示例子或指出正确的方向来探究这个问题,这样我就能读懂它了?任何关于如何衡量绩效的建议都将是非常棒的。

13 个解决方案

#1


66  

Based on this setup:

在此基础上设置:

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

Array.reverse(); is the first or second slowest!

Array.reverse();是第一或第二慢的!

The benchmarks are here: http://jsperf.com/js-array-reverse-vs-while-loop/5

这里的基准是:http://jsperf.com/js-array-reverse-vs-while-loop/5

Across browsers, swap loops are faster. There are two common types of swap algorithms (see Wikipedia), each with two variations.

跨浏览器的交换循环速度更快。有两种常见的交换算法(参见Wikipedia),每种算法都有两种变体。

The two types of swap algorithms are temporary swap and XOR swap.

两种交换算法是临时交换和XOR交换。

The two variations handle index calculations differently. The first variation compares the current left index and the right index and then decrements the right index of the array. The second variation compares the current left index and the length divided by half and then recalculates the right index for each iteration.

这两个变量处理索引的方式不同。第一个变量比较当前左索引和右索引,然后递减数组的右索引。第二个变量比较当前左索引和长度除以二分之一,然后为每次迭代重新计算右索引。

You may or may not see huge differences between the two variations. For example, in Chrome 18, the first variations of the temporary swap and XOR swap are over 60% slower than the second variations, but in Opera 12, both variations of the temporary swap and XOR swap have similar performance.

您可能看到了这两个变体之间的巨大差异,也可能看不到。例如,在Chrome 18中,临时交换和XOR交换的第一个变体比第二个变体慢60%以上,但是在Opera 12中,临时交换和XOR交换的两个变体都具有类似的性能。

Temporary swap:

临时互换:

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

Second variation:

第二个变化:

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:

XOR互换:

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

Second variation:

第二个变化:

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

There is another swap method called destructuring assignment: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

还有一种交换方法叫做析构赋值:http://wiki.ecmascript.org/doku.php?id=harmony:析构

Destructuring assignment:

解构的任务:

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

Second variation:

第二个变化:

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

Right now, an algorithm using destructuring assignment is the slowest of them all. It is even slower than Array.reverse();. However, the algorithms using destructuring assignments and Array.reverse(); methods are the shortest examples, and they look the cleanest. I hope their performance gets better in the future.

目前,使用析构赋值的算法是所有算法中最慢的。它甚至比Array.reverse()还要慢。但是,使用析构赋值和Array.reverse()的算法;方法是最短的例子,而且看起来最干净。我希望他们的表现在将来会变得更好。


Another mention is that modern browsers are improving their performance of array push and splice operations.

另一个值得一提的是,现代浏览器正在改进阵列推送和拼接操作的性能。

In Firefox 10, this for loop algorithm using array push and splice rivals the temporary swap and XOR swap loop algorithms.

在Firefox 10中,这个for循环算法使用数组push和splice来竞争临时交换和XOR交换循环算法。

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

However, you should probably stick with the swap loop algorithms until many of the other browsers match or exceed their array push and splice performance.

但是,您应该坚持使用交换循环算法,直到许多其他浏览器匹配或超过它们的数组push和splice性能。

#2


17  

Native methods are always faster.

本地方法总是更快。

So use Array.reverse where possible. Otherwise an implementation that runs in O(1) would be best ;)

所以使用数组。在可能的情况下。否则,运行在O(1)中的实现将是最好的;

Otherwise just use something like this

否则就像这样

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

Benchmark!

基准!

Interesting the loop is faster if you use all three stages of the for construct instead of only one.

有趣的是,如果您使用for构造的所有三个阶段,而不是仅使用一个,循环就会更快。

for(var i = ii - 1; i !== 0;i--) is faster then var i = ii - 1;for(;i-- !== 0;)

for(var i = ii - 1;我! = = 0;我——)更快然后var = 2 - 1;为(;我——! = = 0;)

#3


10  

I opened a Firefox bug about slow reverse performance in Firefox. Someone from Mozilla looked at the benchmark used in the accepted post, and says that it is pretty misleading -- in their analysis the native method is better in general for reversing arrays. (As it should be!)

我打开了一个关于Firefox反向缓慢性能的Firefox bug。Mozilla的一些人查看了在已接受的帖子中使用的基准,并说这是相当误导人的——在他们的分析中,本机方法通常更适合于反转数组。(应有!)

#4


9  

In simple way you can do this using map.

简单地说,您可以使用map来实现这一点。

let list = [10, 20, 30, 60, 90]
let reversedList = list.map((e, i, a)=> a[(a.length -1) -i]) // [90, 60...]

#5


4  

Since no one came up with it and to complete the list of ways to reverse an array...

因为没有人想到它,也没有完成一个排列的方法列表……

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

It's twice as fast as both while-approaches, but other than that, horribly slow.

它的速度是这两种方法的两倍,但除此之外,速度非常慢。

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

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

#6


3  

Swap functions are the fastest. Here's a reverse function I wrote that is only slightly similar to the swap functions mentioned above but performs faster.

交换函数是最快的。这是我写的一个反向函数,它与上面提到的交换函数稍有相似,但性能更快。

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

You can find the benchmarking here http://jsperf.com/js-array-reverse-vs-while-loop/19

您可以在这里找到基准http://jsperf.com/js-array-reverse-vs- whill -loop/19

#7


2  

Here's a java example http://www.leepoint.net/notes-java/data/arrays/arrays-ex-reverse.html showing how to reverse an array. Very easy to convert to javascript.

这里有一个java示例:http://www.leepoint.net/nots-java/data/arrays/arrays/arrays-ex -reverse.html,显示如何反转数组。很容易转换成javascript。

I would suggest using something that simply captures the time before the function is called, and after the function is called. Which ever takes the least time / clock cycles will be the fastest.

我建议使用一些简单的方法来捕获函数调用前和函数调用后的时间。用最少的时间/时钟周期将是最快的。

#8


1  

If you want to copy a reversed version of an array and keep the original as it is:

如果你想复制一个反向版本的数组,并保持原样:

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

Output of b:

b的输出:

[ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

#9


1  

Here is another example to permanently modify the array reversing it's elements:

下面是另一个永久修改数组元素的例子:

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"]

#10


1  

Here are a couple of tricks I found. Credit goes to Codemanx for the original solution of

下面是我发现的一些技巧。信用证到Codemanx进行原始的解决

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

In Typescript, this can be simplified to just one line

在打字稿中,这可以简化为一行

array.sort(() => 1)

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

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

Since this will be the future of JavaScript, I thought I'd share that.

因为这将是JavaScript的未来,所以我想和大家分享一下。

Here's another trick if your array only has 2 elements

如果你的数组只有两个元素,这里还有一个技巧

array.push(array.shift());

#11


1  

Another suggestion, similar to the above, but using splice instead:

另一个建议,类似于上面的,但是使用splice代替:

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

#12


1  

This is the most efficient and clean way to reverse an array with the ternary operator.

这是使用三元运算符反转数组的最有效、最干净的方法。

function reverse(arr) {
  return arr.length < 2 ? arr : [arr.pop()].concat(reverse(arr));
}
console.log(reverse([4, 3, 3, 1]));

#13


0  

I found a simple way to do this with .slice().reverse()

我找到了一种使用.slice().reverse()的简单方法

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

console.log(reverseArray)

You will get

你会得到

["etc", "...", "third", "second", "first"]

#1


66  

Based on this setup:

在此基础上设置:

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

Array.reverse(); is the first or second slowest!

Array.reverse();是第一或第二慢的!

The benchmarks are here: http://jsperf.com/js-array-reverse-vs-while-loop/5

这里的基准是:http://jsperf.com/js-array-reverse-vs-while-loop/5

Across browsers, swap loops are faster. There are two common types of swap algorithms (see Wikipedia), each with two variations.

跨浏览器的交换循环速度更快。有两种常见的交换算法(参见Wikipedia),每种算法都有两种变体。

The two types of swap algorithms are temporary swap and XOR swap.

两种交换算法是临时交换和XOR交换。

The two variations handle index calculations differently. The first variation compares the current left index and the right index and then decrements the right index of the array. The second variation compares the current left index and the length divided by half and then recalculates the right index for each iteration.

这两个变量处理索引的方式不同。第一个变量比较当前左索引和右索引,然后递减数组的右索引。第二个变量比较当前左索引和长度除以二分之一,然后为每次迭代重新计算右索引。

You may or may not see huge differences between the two variations. For example, in Chrome 18, the first variations of the temporary swap and XOR swap are over 60% slower than the second variations, but in Opera 12, both variations of the temporary swap and XOR swap have similar performance.

您可能看到了这两个变体之间的巨大差异,也可能看不到。例如,在Chrome 18中,临时交换和XOR交换的第一个变体比第二个变体慢60%以上,但是在Opera 12中,临时交换和XOR交换的两个变体都具有类似的性能。

Temporary swap:

临时互换:

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

Second variation:

第二个变化:

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:

XOR互换:

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

Second variation:

第二个变化:

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

There is another swap method called destructuring assignment: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

还有一种交换方法叫做析构赋值:http://wiki.ecmascript.org/doku.php?id=harmony:析构

Destructuring assignment:

解构的任务:

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

Second variation:

第二个变化:

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

Right now, an algorithm using destructuring assignment is the slowest of them all. It is even slower than Array.reverse();. However, the algorithms using destructuring assignments and Array.reverse(); methods are the shortest examples, and they look the cleanest. I hope their performance gets better in the future.

目前,使用析构赋值的算法是所有算法中最慢的。它甚至比Array.reverse()还要慢。但是,使用析构赋值和Array.reverse()的算法;方法是最短的例子,而且看起来最干净。我希望他们的表现在将来会变得更好。


Another mention is that modern browsers are improving their performance of array push and splice operations.

另一个值得一提的是,现代浏览器正在改进阵列推送和拼接操作的性能。

In Firefox 10, this for loop algorithm using array push and splice rivals the temporary swap and XOR swap loop algorithms.

在Firefox 10中,这个for循环算法使用数组push和splice来竞争临时交换和XOR交换循环算法。

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

However, you should probably stick with the swap loop algorithms until many of the other browsers match or exceed their array push and splice performance.

但是,您应该坚持使用交换循环算法,直到许多其他浏览器匹配或超过它们的数组push和splice性能。

#2


17  

Native methods are always faster.

本地方法总是更快。

So use Array.reverse where possible. Otherwise an implementation that runs in O(1) would be best ;)

所以使用数组。在可能的情况下。否则,运行在O(1)中的实现将是最好的;

Otherwise just use something like this

否则就像这样

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

Benchmark!

基准!

Interesting the loop is faster if you use all three stages of the for construct instead of only one.

有趣的是,如果您使用for构造的所有三个阶段,而不是仅使用一个,循环就会更快。

for(var i = ii - 1; i !== 0;i--) is faster then var i = ii - 1;for(;i-- !== 0;)

for(var i = ii - 1;我! = = 0;我——)更快然后var = 2 - 1;为(;我——! = = 0;)

#3


10  

I opened a Firefox bug about slow reverse performance in Firefox. Someone from Mozilla looked at the benchmark used in the accepted post, and says that it is pretty misleading -- in their analysis the native method is better in general for reversing arrays. (As it should be!)

我打开了一个关于Firefox反向缓慢性能的Firefox bug。Mozilla的一些人查看了在已接受的帖子中使用的基准,并说这是相当误导人的——在他们的分析中,本机方法通常更适合于反转数组。(应有!)

#4


9  

In simple way you can do this using map.

简单地说,您可以使用map来实现这一点。

let list = [10, 20, 30, 60, 90]
let reversedList = list.map((e, i, a)=> a[(a.length -1) -i]) // [90, 60...]

#5


4  

Since no one came up with it and to complete the list of ways to reverse an array...

因为没有人想到它,也没有完成一个排列的方法列表……

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

It's twice as fast as both while-approaches, but other than that, horribly slow.

它的速度是这两种方法的两倍,但除此之外,速度非常慢。

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

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

#6


3  

Swap functions are the fastest. Here's a reverse function I wrote that is only slightly similar to the swap functions mentioned above but performs faster.

交换函数是最快的。这是我写的一个反向函数,它与上面提到的交换函数稍有相似,但性能更快。

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

You can find the benchmarking here http://jsperf.com/js-array-reverse-vs-while-loop/19

您可以在这里找到基准http://jsperf.com/js-array-reverse-vs- whill -loop/19

#7


2  

Here's a java example http://www.leepoint.net/notes-java/data/arrays/arrays-ex-reverse.html showing how to reverse an array. Very easy to convert to javascript.

这里有一个java示例:http://www.leepoint.net/nots-java/data/arrays/arrays/arrays-ex -reverse.html,显示如何反转数组。很容易转换成javascript。

I would suggest using something that simply captures the time before the function is called, and after the function is called. Which ever takes the least time / clock cycles will be the fastest.

我建议使用一些简单的方法来捕获函数调用前和函数调用后的时间。用最少的时间/时钟周期将是最快的。

#8


1  

If you want to copy a reversed version of an array and keep the original as it is:

如果你想复制一个反向版本的数组,并保持原样:

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

Output of b:

b的输出:

[ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

#9


1  

Here is another example to permanently modify the array reversing it's elements:

下面是另一个永久修改数组元素的例子:

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"]

#10


1  

Here are a couple of tricks I found. Credit goes to Codemanx for the original solution of

下面是我发现的一些技巧。信用证到Codemanx进行原始的解决

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

In Typescript, this can be simplified to just one line

在打字稿中,这可以简化为一行

array.sort(() => 1)

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

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

Since this will be the future of JavaScript, I thought I'd share that.

因为这将是JavaScript的未来,所以我想和大家分享一下。

Here's another trick if your array only has 2 elements

如果你的数组只有两个元素,这里还有一个技巧

array.push(array.shift());

#11


1  

Another suggestion, similar to the above, but using splice instead:

另一个建议,类似于上面的,但是使用splice代替:

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

#12


1  

This is the most efficient and clean way to reverse an array with the ternary operator.

这是使用三元运算符反转数组的最有效、最干净的方法。

function reverse(arr) {
  return arr.length < 2 ? arr : [arr.pop()].concat(reverse(arr));
}
console.log(reverse([4, 3, 3, 1]));

#13


0  

I found a simple way to do this with .slice().reverse()

我找到了一种使用.slice().reverse()的简单方法

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

console.log(reverseArray)

You will get

你会得到

["etc", "...", "third", "second", "first"]