21

I have this array:

var arr1 = ['a1', 'a2', 'a3', 'a4', 'a5'];

I need to shift it to right by say 2 locations, like

arr1 = ['a4', 'a5', 'a1', 'a2', 'a3']; 

This works for left shift:

arr1 = arr1.concat(arr1.splice(0,2)); // shift left by 2

I get :

arr1 = ['a3', 'a4', 'a5', 'a1', 'a2']; 

But I don't know how to do shift right...

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
mike44
  • 802
  • 5
  • 15
  • 36

3 Answers3

26

You can use .pop() to get the last item and .unshift() to put it at the front:

function shiftArrayToRight(arr, places) {
    for (let i = 0; i < places; i++) {
        arr.unshift(arr.pop());
    }
}

Edit: Ten years later, I'm not sure why I originally suggested that brute force approach using a loop. You can do this without a loop by passing a negative number to splice:

arr.unshift(...arr.splice(-2));

Passing a negative number to .splice() removes that many elements from the end of the array and returns them, and .unshift() inserts each argument at the beginning of the array.

Also, for your original shift left code, you can use .push() instead of .concat() and avoid the need to assign the array back to itself.

arr.push(...arr.splice(0, 2));
gilly3
  • 87,962
  • 25
  • 144
  • 176
  • 2
    would be good to return the array – EugenSunic Nov 03 '20 at 10:01
  • @EugenSunic Returning the array might imply that the function returns a new array that is a shifted copy of the array. By explicitly not returning the array, there's no doubt that this is a mutator function. – gilly3 Feb 13 '23 at 17:15
21

Shift to right to N positions == shift to left to array.length - N positions.

So to shift right on 2 positions for you array - just shift it left on 3 positions.

There is no reason to implement another function as soon as you already have one. Plus solutions with shift/unshift/pop in a loop barely will be as efficient as splice + concat

zerkms
  • 249,484
  • 69
  • 436
  • 539
11

Using .concat() you're building a new Array, and replacing the old one. The problem with that is that if you have other references to the Array, they won't be updated, so they'll still hold the unshifted version.

To do a right shift, and actually mutate the existing Array, you can do this:

arr1.unshift.apply(arr1, arr1.splice(3,2));

The unshift() method is variadic, and .apply lets you pass multiple arguments stored in an Array-like collection.

So the .splice() mutates the Array by removing the last two, and returning them, and .unshift() mutates the Array by adding the ones returned by .splice() to the beginning.


The left shift would be rewritten similar to the right shift, since .push() is also variadic:

arr1.push.apply(arr1, arr1.splice(0,2));