programing tip

Javascript에서 배열을 뒤집는 가장 효율적인 방법은 무엇입니까?

itbloger 2020. 12. 15. 08:17
반응형

Javascript에서 배열을 뒤집는 가장 효율적인 방법은 무엇입니까?


최근 Javascript에서 배열을 뒤집는 가장 효율적인 방법이 무엇인지 물었습니다. 지금은 for 루프를 사용하고 배열을 다루도록 제안했지만 네이티브 Array.reverse()메서드 가 있음을 깨달았습니다 .

호기심을 위해, 누군가 내가 이것을 읽을 수 있도록 예제를 보여 주거나 올바른 방향을 가리킴으로써 이것을 탐구하도록 도울 수 있습니까? 성능을 측정하는 방법에 대한 제안도 훌륭합니다.


이 설정을 기반으로 :

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

Array.reverse(); 첫 번째 또는 두 번째로 느립니다!

벤치 마크는 다음과 같습니다. http://jsperf.com/js-array-reverse-vs-while-loop/5

브라우저에서 스왑 루프가 더 빠릅니다. 두 가지 일반적인 유형의 스왑 알고리즘 ( Wikipedia 참조 )이 있으며 각각 두 가지 변형이 있습니다.

두 가지 유형의 스왑 알고리즘은 임시 스왑과 XOR 스왑입니다.

두 변형은 인덱스 계산을 다르게 처리합니다. 첫 번째 변형은 현재 왼쪽 인덱스와 오른쪽 인덱스를 비교 한 다음 배열의 오른쪽 인덱스를 감소시킵니다. 두 번째 변형은 현재 왼쪽 인덱스와 길이를 절반으로 나눈 값을 비교 한 다음 각 반복에 대해 오른쪽 인덱스를 다시 계산합니다.

두 변형 사이에 큰 차이가있을 수도 있고 그렇지 않을 수도 있습니다. 예를 들어 Chrome 18에서 임시 스왑 및 XOR 스왑의 첫 번째 변형은 두 번째 변형보다 60 % 이상 느리지 만 Opera 12에서는 임시 스왑과 XOR 스왑의 두 변형 모두 유사한 성능을 보입니다.

임시 스왑 :

첫 번째 변형 :

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

두 번째 변형 :

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 스왑 :

첫 번째 변형 :

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

두 번째 변형 :

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

Destructuring Assignment라는 또 다른 스왑 방법이 있습니다 : http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

구조 해제 할당 :

첫 번째 변형 :

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

두 번째 변형 :

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

지금은 구조 해제 할당을 사용하는 알고리즘이 가장 느립니다. 보다 느립니다 Array.reverse();. 그러나 비 구조화 할당 및 Array.reverse();방법을 사용하는 알고리즘 은 가장 짧은 예이며 가장 깔끔해 보입니다. 앞으로 그들의 실적이 좋아 졌으면 좋겠습니다.


또 다른 언급은 최신 브라우저가 어레이 pushsplice운영 성능을 개선하고 있다는 것 입니다.

Firefox 10에서 for배열을 사용하는 루프 알고리즘 은 임시 스왑 및 XOR 스왑 루프 알고리즘 pushsplice경쟁합니다.

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

그러나 다른 많은 브라우저가 어레이 pushsplice성능 일치하거나 초과 할 때까지 스왑 루프 알고리즘을 고수해야 합니다.


네이티브 메서드는 항상 더 빠릅니다.

따라서 Array.reverse가능하면 사용 하십시오. 그렇지 않으면 실행되는 구현이 O(1)가장 좋습니다.)

그렇지 않으면 다음과 같이 사용하십시오.

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

기준!

for하나만 사용하는 대신 구성 의 세 단계를 모두 사용하면 루프가 더 빠릅니다 .

for(var i = ii - 1; i !== 0;i--) 더 빠르다 var i = ii - 1;for(;i-- !== 0;)


간단한 방법으로지도를 사용하여이를 수행 할 수 있습니다.

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

나는 파이어 폭스 버그를 오픈 파이어 폭스에서 느린 역의 성능에 대해. Mozilla의 누군가가 승인 된 게시물에 사용 된 벤치 마크를 살펴 보았고 이는 상당히 오해의 소지가 있다고 말합니다. 분석에서 일반적으로 배열을 뒤집는 데 기본 방법이 더 좋습니다. (그렇게해야합니다!)


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


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


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

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.

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.


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

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


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:

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

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

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

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.

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

array.push(array.shift());

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

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

console.log(reverseArray)

You will get

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

You could also make use of reduceRight which will iterate through each value of the array (from right-to-left)

const myArray = [1, 2, 3, 4, 5]
const reversedArray = myArray.reduceRight((acc, curr) => [...acc, curr], [])
console.log(reversedArray) // [5, 4, 3, 2, 1]


Pasting the below into any javascript runtime console either on the browser or node.js would do a straight way benchmark test on a large array of number.

Say 40,000 in my case

var array = Array.from({ length: 40000 }, () =>
  Math.floor(Math.random() * 40000)
);
var beforeStart = Date.now();
var reversedArray = array.map((obj, index, passedArray) => {
  return passedArray[passedArray.length - index - 1];
});
console.log(reversedArray);
var afterCustom = Date.now();
console.log(array.reverse());
var afterNative = Date.now();
console.log(`custom took : ${afterCustom - beforeStart}ms`);
console.log(`native took : ${afterNative - afterCustom}ms`);

You can simply run the snippet directly to see how the custom version fare too.

ReferenceURL : https://stackoverflow.com/questions/5276953/what-is-the-most-efficient-way-to-reverse-an-array-in-javascript

반응형