Rotate the elements in an array in JavaScript

Viewed 130821

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 right, and a negative n to the left (-length < n < length) :

Array.prototype.rotateRight = function( n ) {
  this.unshift( this.splice( n, this.length ) );
}

Which can then be used this way:

var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
months.rotate( new Date().getMonth() );

My original version above has a flaw, as pointed out by Christoph in the comments bellow, a correct version is (the additional return allows chaining):

Array.prototype.rotateRight = function( n ) {
  this.unshift.apply( this, this.splice( n, this.length ) );
  return this;
}

Is there a more compact and/or faster solution, possibly in the context of a JavaScript framework? (none of the proposed versions bellow is either more compact or faster)

Is there any JavaScript framework out there with an array rotate built-in? (Still not answered by anyone)

40 Answers

Type-safe, generic version which mutates the array:

Array.prototype.rotate = (function() {
    // save references to array functions to make lookup faster
    var push = Array.prototype.push,
        splice = Array.prototype.splice;

    return function(count) {
        var len = this.length >>> 0, // convert to uint
            count = count >> 0; // convert to int

        // convert count to value in range [0, len)
        count = ((count % len) + len) % len;

        // use splice.call() instead of this.splice() to make function generic
        push.apply(this, splice.call(this, 0, count));
        return this;
    };
})();

In the comments, Jean raised the issue that the code doesn't support overloading of push() and splice(). I don't think this is really useful (see comments), but a quick solution (somewhat of a hack, though) would be to replace the line

push.apply(this, splice.call(this, 0, count));

with this one:

(this.push || push).apply(this, (this.splice || splice).call(this, 0, count));

Using unshift() instead of push() is nearly twice as fast in Opera 10, whereas the differences in FF were negligible; the code:

Array.prototype.rotate = (function() {
    var unshift = Array.prototype.unshift,
        splice = Array.prototype.splice;

    return function(count) {
        var len = this.length >>> 0,
            count = count >> 0;

        unshift.apply(this, splice.call(this, count % len, len));
        return this;
    };
})();

I would probably do something like this:

Array.prototype.rotate = function(n) {
    n = n % this.length;
    return this.slice(n, this.length).concat(this.slice(0, n));
}

Edit    Here’s a mutator version:

Array.prototype.rotate = function(n) {
    n = n % this.length;
    while (this.length && n < 0) n += this.length;
    this.push.apply(this, this.splice(0, n));
    return this;
}

Using ES6's spread for an immutable example ...

[...array.slice(1, array.length), array[0]]

and

[array[array.items.length -1], ...array.slice(0, array.length -1)]

It's probably not the most efficient though but it's concise.

Easy solution with slice and destructuring:

const rotate = (arr, count = 1) => {
  return [...arr.slice(count, arr.length), ...arr.slice(0, count)];
};

const arr = [1,2,3,4,5];

console.log(rotate(arr, 1));  // [2, 3, 4, 5, 1]
console.log(rotate(arr, 2));  // [3, 4, 5, 1, 2]
console.log(rotate(arr, -2)); // [4, 5, 1, 2, 3]
console.log(rotate(arr, -1)); // [5, 1, 2, 3, 4]

function rotate(arr, k) {
for (var i = 0; i < k+1; i++) {
    arr.push(arr.shift());
}
return arr;
}
//k work as an index array
console.log(rotate([1, 2, 7, 4, 5, 6, 7], 3)); //[5,6,7,1,2,7,4]
console.log(rotate([-1, -100, 3, 99], 2));     //[99,-1,-100,3]
// 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)];

Update Feb 2021

A one-liner functions to perform rotate right and rotate left of array elements.

Rotate Left

const arrRotateLeft = (a,n) =>{while (n>0) {a.push(a.shift());n--;}return a;};

Rotate Right

const arrRotateRight= (a,n) =>{while (n>0) {a.unshift(a.pop());n--;}return a;};

const arrRotateLeft = (a,n)=>{while (n>0) {a.push(a.shift());n--;}return a;};

const arrRotateRight= (a,n)=>{while (n>0) {a.unshift(a.pop());n--;}return a;};


//=========== Test rotate Left =================
console.log(arrRotateLeft([1,2,3,4,5,6],0));       // [1,2,3,4,5,6]   <== rotate in this direction
console.log(arrRotateLeft([1,2,3,4,5,6],1));       // [2,3,4,5,6,1]
console.log(arrRotateLeft([1,2,3,4,5,6],2));       // [3,4,5,6,1,2]
console.log(arrRotateLeft([1,2,3,4,5,6],3));       // [4,5,6,1,2,3]
console.log(arrRotateLeft([1,2,3,4,5,6,7,8],5));   // [6,7,8,1,2,3,4,5]


//=========== Test rotate Right =================
console.log(arrRotateRight([1,2,3,4,5,6],0));      // [1,2,3,4,5,6]   ==> rotate in this direction
console.log(arrRotateRight([1,2,3,4,5,6],1));      // [6,1,2,3,4,5]
console.log(arrRotateRight([1,2,3,4,5,6],2));      // [5,6,1,2,3,4]
console.log(arrRotateRight([1,2,3,4,5,6],3));      // [4,5,6,1,2,3]
console.log(arrRotateRight([1,2,3,4,5,6,7,8],5));  // [4,5,6,7,8,1,2,3]

This function is a little faster than the accepted answer for small arrays but MUCH faster for large arrays. This function also allows for an arbitrary number of rotations greater than the length of the array, which is a limitation of the original function.

Lastly, the accepted answer rotates the opposite direction as described.

const rotateForEach = (a, n) => {
    const l = a.length;
    a.slice(0, -n % l).forEach(item => a.push( item ));
    return a.splice(n % l > 0 ? (-n % l) : l + (-n % l));
}

And the functional equivalent (which seems to also have some performance benefits):

const rotateReduce = (arr, n) => {
    const l = arr.length;
    return arr.slice(0, -n % l).reduce((a,b) => {
        a.push( b );
        return a;
    }, arr).splice(n % l> 0 ? l + (-n % l) : -n % l);
};

You can check out the performance breakdown here.

EDIT:: Hey so turns out there's too much iteration happening. No loops, no branching.

Still works with negative n for right rotation and positive n for left rotation for any size n, Mutation free

function rotate(A,n,l=A.length) {
  const offset = (((n % l) + l) %l)
  return A.slice(offset).concat(A.slice(0,offset))
}

Here's the code golf version for giggles

const r = (A,n,l=A.length,i=((n%l)+l)%l)=>A.slice(i).concat(A.slice(0,i))

EDIT1::* Branchless, mutationless implementation.

So hey, turns out I had a branch where I didn't need it. Here is a working solution. negative num = right rotate by |num| positive num = left rotate by num

function r(A,n,l=A.length) {
  return A.map((x,i,a) => A[(((n+i)%l) + l) % l])
}

The equation ((n%l) + l) % l maps exactly positive and negative numbers of any arbitrarily large values of n

ORIGINAL

Rotate left and right. Rotate left with positive n, rotate right with negative n.

Works for obscenely large inputs of n.

No mutation mode. Too much mutation in these answers.

Also, fewer operations than most answers. No pop, no push, no splice, no shift.

const rotate = (A, num ) => {
   return A.map((x,i,a) => {
      const n = num + i
      return n < 0 
        ? A[(((n % A.length) + A.length) % A.length)]
        : n < A.length 
        ? A[n] 
        : A[n % A.length]
   })
}

or

 const rotate = (A, num) => A.map((x,i,a, n = num + i) => 
  n < 0
    ? A[(((n % A.length) + A.length) % A.length)]
    : n < A.length 
    ? A[n] 
    : A[n % A.length])

//test
rotate([...Array(5000).keys()],4101)   //left rotation
rotate([...Array(5000).keys()],-4101000)  //right rotation, num is negative

// will print the first index of the array having been rotated by -i
// demonstrating that the rotation works as intended
[...Array(5000).keys()].forEach((x,i,a) => {
   console.log(rotate(a,-i)[0])
}) 
// prints even numbers twice by rotating the array by i * 2 and getting the first value
//demonstrates the propper mapping of positive number rotation when out of range
[...Array(5000).keys()].forEach((x,i,a) => {
   console.log(rotate(a,i*2)[0])
})

Explanation:

map each index of A to the value at index offset. In this case

offset = num

if the offset < 0 then offset + index + positive length of A will point to the inverse offset.

if offset > 0 and offset < length of A then simply map the current index to the offset index of A.

Otherwise, modulo the offset and the length to map the offset in the bounds of the array.

Take for instance offset = 4 and offset = -4.

When offset = -4, and A = [1,2,3,4,5], for each index, offset + index will make the magnitude (or Math.abs(offset)) smaller.

Let's explain the calculation for the index of negative n first. A[(((n % A.length) + A.length) % A.length)+0] and been intimidated. Don't be. It took me 3 minutes in a Repl to work it out.

  1. We know n is negative because the case is n < 0. If the number is larger than the range of the Array, n % A.length will map it into the range.
  2. n + A.length add that number to A.length to offset n the correct amount.
  3. We know n is negative because the case is n < 0. n + A.length add that number to A.length to offset n the correct amount.
  4. Next Map it to the range of the length of A using modulo. The second modulous is necessary to map the result of the calculation into an indexable range

    enter image description here

  5. First index: -4 + 0 = -4. A.length = 5. A.length - 4 = 1. A2 is 2. Map index 0 to 2. [2,... ]

  6. Next index, -4 + 1 = -3. 5 + -3 = 2. A2 is 3. Map index 1 to 3. [2,3... ]
  7. Etc.

The same process applies to offset = 4. When offset = -4, and A = [1,2,3,4,5], for each index, offset + index will make the magnitude bigger.

  1. 4 + 0 = 0. Map A[0] to the value at A[4]. [5...]
  2. 4 + 1 = 5, 5 is out of bounds when indexing, so map A2 to the value at the remainder of 5 / 5, which is 0. A2 = value at A[0]. [5,1...]
  3. repeat.

Don't use concat or splice or anything else. Use .map or a while loop for a simple, efficient way to rotate left or right. The idea is to iterate for the length of the original array. At each iteration, update the index of the next value in the rotation to be added to the newly rotated array. This solution is O(n) time complexity---just one loop in both examples.

Map:

function Rotate(arr, n) {
  if (n === 0) {
    return arr;
  }

  var left = n < 0;
  n = Math.abs(left ? n : arr.length - n);

  return arr.map(() => {
    n = n < arr.length ? n : 0;

    return arr[n++];
  });
}

var array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var places = 4;

console.log(Rotate(array, places));//[12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
console.log(Rotate(array, -places));//[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3]

While:

function Rotate(arr, n) {
  if (n === 0) {
    return arr;
  }

  var rotatedArray = [];
  var left = n < 0;
  n = Math.abs(left ? n : arr.length - n);

  while (rotatedArray.length < arr.length) {
    n = n < arr.length ? n : 0;
    rotatedArray.push(arr[n++]);
  }

  return rotatedArray;
}

The splice and concat methods are O(n) operations; the former removes and then returns an array of "spliced" values, and the latter returns a new array with the values of the merged arrays. So, if you're using them both, you're doing too much work: O(n) * 2 and also two newly copied arrays. And frankly, it's easier to see the logic of what's happening with a simple while loop.

for rotating the array by 'd' places towards the left we can use unshift() and pop().

   var arr=[1,2,3,4,5],d=4;
   for(var i=d;i<arr.length;i++)
    arr.unshift(arr.pop());
    console.log(arr);

for hacker rank, problem-solving DS left and right rotation problem solution(javascript, java) checkout my below article

https://webdev99.com/left-rotationproblem-solving-data-structures/

Follow a simpler approach of running a loop to n numbers and shifting places upto that element.

function arrayRotateOne(arr, n) {
  for (let i = 0; i < n; i++) {
    arr.unshift(arr.pop());
  }
  return arr;
}
console.log( arrayRotateOne([1,2,3,4,5,6],2));



function arrayRotateOne(arr,n) {
  for(let i=0; i<n;i++){
      arr.push(arr.shift());
      console.log('execute',arr)
    }
     return arr;
 }

console.log( arrayRotateOne([1,2,3,4,5,6],2));

Non mutating solution

var arr = ['a','b','c','d']
arr.slice(1,arr.length).concat(arr.slice(0,1)

with mutation

var arr = ['a','b','c','d']
arr = arr.concat(arr.splice(0,1))

I am sharing my solution which I am using for rotating on carousel. It might break when array size is smaller than displayCount, but you could add extra condition to stop rotating when it's small, or concatenating the main array *displayCount times too.

function rotate(arr, moveCount, displayCount) {
  const size = arr.length;

  // making sure startIndex is between `-size` and `size`
  let startIndex = moveCount % size;
  if (startIndex < 0) startIndex += size; 

  return [...arr, ...arr].slice(startIndex, startIndex + displayCount);
}

// move 3 to the right and display 4 items
// rotate([1,2,3,4,5], 3, 4) -> [4,5,1,2]

// move 3 to the left and display 4 items
// rotate([1,2,3,4,5], -3, 4) -> [3,4,5,1]

// move 11 to the right and display 4
// rotate([1,2,3,4,5], 3, 4) -> [2,3,4,5]

How about incrementing a counter and then getting the remainder of a division by the array length to get where you are supposed to be.

var i = 0;
while (true);
{
    var position = i % months.length;
    alert(months[position]);
    ++i;
}

Language syntax aside this should work fine.

If your array is going to be large and/or you are going to rotate a lot, you might want to consider using a linked list instead of an array.

I am not sure if this is the most efficient way but I like the way it reads, it's fast enough for most large tasks as I have tested it on production...

function shiftRight(array) {
  return array.map((_element, index) => {
    if (index === 0) {
      return array[array.length - 1]
    } else return array[index - 1]
  })
}

function test() {
  var input = [{
    name: ''
  }, 10, 'left-side'];
  var expected = ['left-side', {
    name: ''
  }, 10]
  var actual = shiftRight(input)

  console.log(expected)
  console.log(actual)

}

test()

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

** Using Latest version of JS we can build it every easily **

 Array.prototype.rotateLeft = function (n) {
   this.unshift(...this.splice(-(n), n));
    return this
  }

here moves: number of rotations ,a Array that you can pass random number

let a = [1, 2, 3, 4, 5, 6, 7];
let moves = 4;
let output = a.rotateLeft(moves);
console.log("Result:", output)

Array in JS has below built in method which can be used to rotate an array quite easily and obviously these methods are immutable in nature.

  • push: Inserts the item to end of the array.
  • pop: Removes the item from the end of the array.
  • unshift: Inserts the item to the beginning of the array.
  • shift: Removes the item from the beginning of the array.

The below solution (ES6) takes two arguments , array needs to be rotated and n , number of times the array should be rotated.

const rotateArray = (arr, n) => {
  while(arr.length && n--) {
    arr.unshift(arr.pop());
  }
  return arr;
}

rotateArray(['stack', 'overflow', 'is', 'Awesome'], 2) 
// ["is", "Awesome", "stack", "overflow"]

It can be added to Array.prototype and can be used all across your application

Array.prototype.rotate = function(n) {
 while(this.length && n--) {
   this.unshift(this.pop());
 }
 return this;
}
[1,2,3,4].rotate(3); //[2, 3, 4, 1]

Using for loop. Here are the steps

  1. Store first element of array as temp variable.
  2. Then swap from left to right.
  3. Then assign temp variable to last element of array.
  4. Repeat these steps for number of rotations.

function rotateLeft(arr, rotations) {
    let len = arr.length;
    for(let i=0; i<rotations; i++){ 
        let temp = arr[0];
        for(let i=0; i< len; i++){
            arr[i]=arr[i+1];
        }
        arr[len-1]=temp;
    }
    return arr;
}

let arr = [1,2,3,4,5];

let rotations = 3;
let output = rotateLeft(arr, rotations);
console.log("Result Array => ", output);

with es6 syntax

function rotLeft(a, d) {
    const removed = a.splice(0,d);
    return [...a, ...removed];
}

Use the following -

arr=[1,2,3,4,5]  
let arrs=[]
arrs=arr.slice(d%arr.length).concat(arr.slice(0,d%arr.length))

Where, d is no.of rotations
Best Solution, no need of applying Brute force techniques of Popping Pushing with O(1) time complexity

function solution (months, k) {
    var u = [1];
    for (let i = 0; i < k; i++) {
        months.splice(0, 0, months[months.length - 1]);
        months.splice(months.length-1, 1);
    }
    return months;
}

I did it like this without any helper libraries

function shiftArrayValuesRight(A, K) {
  // where A is the array, K is the number of times to shift
  let b = []
  if(A.length > 0) {
    for(let i = 0; i < K; i++){
      b[0] = A[A.length - 1]
      for(let j = 1; j < A.length; j++) {
        b[j] = A[j-1]
      }
      A = b
      b = []
    }
    return A 
  } else{
      return A
  }
}
let array = [3, 9, 2, 4, 5, 7, 8];

const shiftLeft = (arr = [], n) => {
    for (let index = 0; index < n; index++) {
       arr.push(arr.shift())
    }
 return arr
}

shiftLeft(array, 2)

What about a more functional approach?

const rotate = _.curry((n,v) => {
  const M = v.length;
  const m = ((n % M) + M) % M;
  return _.flatten([_.drop(m, v), _.take(m, v)]);
});

In case negative ns are not expected, it can be simplified to

const rotate = _.curry((n,v) => {
  const N = v.length;
  return _.flatten([_.drop(n % N, v), _.take(n % N, v)]);
});

and in case n is guaranteed to be not greater than v.length, then we can simplify further:

const rotate = _.curry((n,v) => _.flatten([_.drop(n, v), _.take(n, v)]));

Here's one-liner solution that utilizes spreading and slicing.

There are two ways to rotate: if you want to move right, you need to supply a negative value; but if you left, you supply a positive value.

rotateLeft(arr, 1) === rotateRight(arr, -1)

As you can see below, rotating with a positive value naturally moves to the left.

console.json = (json) => console.log(JSON.stringify(json));

const
  rotateLeft  = (arr, n) =>
    n ? [...arr.slice( n, arr.length), ...arr.slice(0,  n)] : arr,
  rotateRight = (arr, n) =>
    n ? [...arr.slice(-n, arr.length), ...arr.slice(0, -n)] : arr;

const arr = [1, 2, 3, 4, 5];

console.log('Rotate left:');
console.json(rotateLeft(arr,  1));  // [2, 3, 4, 5, 1]
console.json(rotateLeft(arr,  2));  // [3, 4, 5, 1, 2]
console.json(rotateLeft(arr, -2));  // [4, 5, 1, 2, 3]
console.json(rotateLeft(arr, -1));  // [5, 1, 2, 3, 4]
console.json(rotateLeft(arr,  0));  // [1, 2, 3, 4, 5] (no-op)

console.log('Rotate right:');
console.json(rotateRight(arr,  1)); // [5, 1, 2, 3, 4]
console.json(rotateRight(arr,  2)); // [4, 5, 1, 2, 3]
console.json(rotateRight(arr, -2)); // [3, 4, 5, 1, 2]
console.json(rotateRight(arr, -1)); // [2, 3, 4, 5, 1]
console.json(rotateRight(arr,  0)); // [1, 2, 3, 4, 5] (no-op)
.as-console-wrapper { top: 0; max-height: 100% !important; }

from 2022

I think this approch is the simplest

// 0. fix the index
// 1. remove the rotation part
// 2. add a reversed version of the rotation part to what left
// done

function rotateArray(array, k) {
    let rev = k > 0;
    array = [...array];
      
    k = ( k + array.length) % array.length; 
    const splice = array.splice(0, k); //... for make a clone;
    return array.concat(rev ? splice.reverse() : splice);
}

console.log(rotateArray([1,2,3,4,5,6,7], 3)) // expect [4,5,6,7,1,2,3]
console.log(rotateArray([1,2,3,4,5,6,7], -3))// expect [5,6,7,1,2,3,4]

Not sure about the efficiency but I would do it in this non mutating way :

 Array.prototype.rotate = function( n ) {
  
   return this.map( (item, index)=> this[ (this.length + index + n)%this.length ] )
 }

Related