Clean way to rotate an array in js?

Clean way to rotate an array in js?
0

#1

I want to rotate through an array like this:

const array = [a,b,c,d];
let counter = 0;
// array[counter] = a
//array[counter-1] = d

and so on. currently I have

function rotate(){
counter -= 1
if(counter === -1){
counter = 3}
}

but that’s a really bulky sollution, especially if I ever want to decrease it by more than 1. Is there a better way to do this?


#2

Hmm do you want to reverse the array?

Check out https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse


#3

no. I want to be able to rotate through the array. so a -> b -> c -> d -> a -> b -> c… etc if I just add 1 to the counter at some point I will have a problem because the index goes only from 0 - 3. if I start at “d” and I want to add 1 I want to be back at a. just like a clock that always rotates from 1 - 12 and then starts over again


#4

Not really sure what you are looking for but using %arr.length on a counter or index will roll it back to zero when you get to end.

Here is a simple demo

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

for( let i = 0, j = 0;j < 25; i = (i+1)%arr.length, j++){
  console.log(arr[i]);
}

The j counter is just to keep this from being an infinite loop.


#5

I’m not sure of the context of your situation, could you please explain what it’s being used for?

To me, the rotation function could be put into context when you have a image gallery slider, and as you click right or left it shows the next/previous image. So if you look at that in terms of an array, it might be something like:

const images = [
      { name: 'Image 001', src: 'https://img_location001.com', key: 0 },
      { name: 'Image 002', src: 'https://img_location002.com', key: 1 },
      { name: 'Image 003', src: 'https://img_location003.com', key: 2 }
]

Without going into it too much, I think you could make this work using .slice() or .splice(). Here is just one way to think about it:

When a user clicks the right button, you would fire the rotate(arr, key) function and pass in the current image’s key so you can then slice it out and push it to the back of the arr array. You could then return the new array. If the user clicks left, then the opposite would happen.

I’d be happy to expand on this if it helps?


#6

@cub3fox, I believe you want to achieve something like this:

const arr = [1, 2, 3, 4, 5];
rotate(arr, -1); //5

…first of all, correct name would be peek(), as you’re not really rotating anything. There are many ways to do this, but I guess the easiest one would be:

function peek(arr, index) {
  return arr.slice(index)[0];
}

#7

Your kinda want a circular queue-like structure. Naively:

function mutableRotateRight (arr) {
 arr.unshift(arr.pop())
 return arr;
}

function mutableRotateLeft (arr) {
  arr.push(arr.shift());
  return arr;
}

And for non-mutating version, make a copy of the array first (arr.slice() or [...arr]). The mutating version should be very fast, but if you’re only using small one-dimensional arrays with primitive values then difference in speed between non-mutating and mutating versions should be negligible, and it’s much easier to deal with non-mutating functions.

As regards specifying a size of rotation, instead of just push/unshift, check on array length to catch any input that would put the rotation out of bounds first and then using splice (or slice() for non-mutating version) is faster than running the push/unshift operation over and over afaik

I’ve had to do this quite a few times, normally for datepicker-ish things (its really useful for cycling through months).

Edit: fairly clean solution if you need to specify size (via SO): https://stackoverflow.com/a/33451102