Rotate the elements in an array in JavaScript

后端 未结 30 1198
走了就别回头了
走了就别回头了 2020-11-22 10:55

I was wondering what was the most efficient way to rotate a JavaScript array.

I came up with this solution, where a positive n rotates the array to the

相关标签:
30条回答
  • 2020-11-22 11:10

    The accepted answer has a flaw of not being able to handle arrays larger than the call stack size which depends on the session but should be around like 100~300K items. For instance, in the current Chrome session that i tried it was 250891. In many cases you may not even know to what size the array might dynamically grow into. So that's a serious problem.

    To overcome this limitation, I guess one interesting method is utilizing Array.prototype.map() and mapping the elements by rearranging the indices in a circular fashion. This method takes one integer argument. If this argument is positive it will rotate on increasing indices and if negative on decreasing indices direction. This has only O(n) time complexity and will return a new array without mutating the one it's called upon while handling millions of items without any problem. Let see how it works;

    Array.prototype.rotate = function(n) {
    var len = this.length;
    return !(n % len) ? this
                      : n > 0 ? this.map((e,i,a) => a[(i + n) % len])
                              : this.map((e,i,a) => a[(len - (len - i - n) % len) % len]);
    };
    var a = [1,2,3,4,5,6,7,8,9],
        b = a.rotate(2);
    console.log(JSON.stringify(b));
        b = a.rotate(-1);
    console.log(JSON.stringify(b));

    Actually after i have been criticized on two matters as follows;

    1. There is no need for a conditional for positive or negative input since it reveals a violation of DRY .you could do this with one map because every negative n has a positive equivalent (Totally right..)
    2. An Array function should either change the current array or make a new array, your function could do either depending on whether a shift is necessary or not (Totally right..)

    I have decided to modify the code as follows;

    Array.prototype.rotate = function(n) {
    var len = this.length;
    return !(n % len) ? this.slice()
                      : this.map((e,i,a) => a[(i + (len + n % len)) % len]);
    };
    var a = [1,2,3,4,5,6,7,8,9],
        b = a.rotate(10);
    console.log(JSON.stringify(b));
        b = a.rotate(-10);
    console.log(JSON.stringify(b));

    Then again; of course the JS functors like Array.prototype.map() are slow compared to their equivalents coded in plain JS. In order to gain more than 100% performance boost the following would probably be my choice of Array.prototype.rotate() if i ever need to rotate an array in production code like the one i used in my attempt on String.prototype.diff()

    Array.prototype.rotate = function(n){
      var len = this.length,
          res = new Array(this.length);
      if (n % len === 0) return this.slice();
      else for (var i = 0; i < len; i++) res[i] = this[(i + (len + n % len)) % len];
      return res;
    };
    
    0 讨论(0)
  • 2020-11-22 11:10

    Native, fast, small, semantic, works on old engines and "curryable".

    function rotateArray(offset, array) {
        offset = -(offset % array.length) | 0 // ensure int
        return array.slice(offset).concat(
            array.slice(0, offset)
        )
    }
    
    0 讨论(0)
  • 2020-11-22 11:11

    @Christoph, you've done a clean code, but 60% slowest than this one i found. Look at the result on jsPerf : http://jsperf.com/js-rotate-array/2 [Edit] OK now there is more browsers an that not obvious witch methods the best

    var rotateArray = function(a, inc) {
        for (var l = a.length, inc = (Math.abs(inc) >= l && (inc %= l), inc < 0 && (inc += l), inc), i, x; inc; inc = (Math.ceil(l / inc) - 1) * inc - l + (l = inc))
        for (i = l; i > inc; x = a[--i], a[i] = a[i - inc], a[i - inc] = x);
        return a;
    };
    
    var array = ['a','b','c','d','e','f','g','h','i'];
    
    console.log(array);
    console.log(rotateArray(array.slice(), -1)); // Clone array with slice() to keep original
    
    0 讨论(0)
  • 2020-11-22 11:12
    // Example of array to rotate
    let arr = ['E', 'l', 'e', 'p', 'h', 'a', 'n', 't'];
    
    // Getting array length
    let length = arr.length;
    
    // rotation < 0 (move left), rotation > 0 (move right)
    let rotation = 5;
    
    // Slicing array in two parts
    let first  = arr.slice(   (length - rotation) % length, length); //['p', 'h', 'a' ,'n', 't']
    let second = arr.slice(0, (length - rotation) % length); //['E', 'l', 'e']
    
    // Rotated element
    let rotated = [...first, ...second]; // ['p', 'h', 'a' ,'n', 't', 'E', 'l', 'e']
    
    

    In one line of code:

    let rotated = [...arr.slice((length - rotation) % length, length), ...arr.slice(0, (length - rotation) % length)];
    
    0 讨论(0)
  • 2020-11-22 11:12

    @molokoloco I needed a function that I could configure to rotate in a direction - true for forward and false for backward. I created a snippet that takes a direction, a counter and an array and outputs an object with the counter incremented in the appropriate direction as well as prior, current, and next values. It does NOT modify the original array.

    I also clocked it against your snippet and although it is not faster, it is faster than the ones you compare yours with - 21% slower http://jsperf.com/js-rotate-array/7 .

    function directionalRotate(direction, counter, arr) {
      counter = direction ? (counter < arr.length - 1 ? counter + 1 : 0) : (counter > 0 ? counter - 1 : arr.length - 1)
      var currentItem = arr[counter]
      var priorItem = arr[counter - 1] ? arr[counter - 1] : arr[arr.length - 1]
      var nextItem = arr[counter + 1] ? arr[counter + 1] : arr[0]
      return {
        "counter": counter,
        "current": currentItem,
        "prior": priorItem,
        "next": nextItem
      }
    }
    var direction = true // forward
    var counter = 0
    var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
    
    directionalRotate(direction, counter, arr)
    
    0 讨论(0)
  • 2020-11-22 11:13

    with es6 syntax

    function rotLeft(a, d) {
        const removed = a.splice(0,d);
        return [...a, ...removed];
    }
    
    0 讨论(0)
提交回复
热议问题