1

Create a function named "rotate" that takes an array and returns a new one with the elements inside rotated n spaces.

If n is greater than 0 it should rotate the array to the right. If n is less than 0 it should rotate the array to the left. If n is 0, then it should return the array unchanged.

Example:

var data = [1, 2, 3, 4, 5];

rotate(data, 1) // => [5, 1, 2, 3, 4]
rotate(data, 2) // => [4, 5, 1, 2, 3]
rotate(data, 3) // => [3, 4, 5, 1, 2]
rotate(data, 4) // => [2, 3, 4, 5, 1]
rotate(data, 5) // => [1, 2, 3, 4, 5]

rotate(data, 0) // => [1, 2, 3, 4, 5]

rotate(data, -1) // => [2, 3, 4, 5, 1]
rotate(data, -2) // => [3, 4, 5, 1, 2]
rotate(data, -3) // => [4, 5, 1, 2, 3]
rotate(data, -4) // => [5, 1, 2, 3, 4]
rotate(data, -5) // => [1, 2, 3, 4, 5]

Furthermore the method should take ANY array of objects and perform this operation on them:

rotate(['a', 'b', 'c'], 1)     // => ['c', 'a', 'b']
rotate([1.0, 2.0, 3.0], 1)     // => [3.0, 1.0, 2.0]
rotate([true, true, false], 1) // => [false, true, true]

Finally, the rotation shouldn't be limited by the indices available in the array. Meaning that if we exceed the indices of the array it keeps rotating.

Example:

var data = [1, 2, 3, 4, 5]
rotate(data, 7)     // => [4, 5, 1, 2, 3]
rotate(data, 11)    // => [5, 1, 2, 3, 4]
rotate(data, 12478) // => [3, 4, 5, 1, 2]
Riaz Bappy
  • 23
  • 5

2 Answers2

1

You could basically do this with a while loop and increment or decrement based on the number parameter, if its positive or negative.

function rotate(data, n) {
  const output = [...data]

  if (n === 0) {
    return data
  }

  const neg = n < 0
  const last = output.length - 1
  const toIndex = neg ? last : 0
  const index = neg ? 0 : last

  while ((neg ? n++ : n--) !== 0) {
    output.splice(toIndex, 0, output.splice(index, 1)[0])
  }

  return output
}


var data = [1, 2, 3, 4, 5];

console.log(rotate(data, 2)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, 3)) // => [3, 4, 5, 1, 2]
console.log(rotate(data, 4)) // => [2, 3, 4, 5, 1]
console.log(rotate(data, 5)) // => [1, 2, 3, 4, 5]


console.log(rotate(data, -1)) // => [2, 3, 4, 5, 1]
console.log(rotate(data, -2)) // => [3, 4, 5, 1, 2]
console.log(rotate(data, -3)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, -4)) // => [5, 1, 2, 3, 4]
console.log(rotate(data, -5)) // => [1, 2, 3, 4, 5]

console.log(rotate(['a', 'b', 'c'], 1))
console.log(rotate([true, true, false], 1))
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
0

This is a non-mutating example avoiding loops:

const rotate = (arr, n) => {

  const i = ((n % arr.length) + arr.length) % arr.length

  if (!i) return [...arr]

  return [...arr.slice(-i), ...arr.slice(0, arr.length - i)]

}

Explanation

The basic idea is that the single most important thing in this calculation is the effective starting index based on the arguments given. We achieve this through the modulo operand which helps us work out the index based on the length of the array and a number which can be greater than the length of the array.

i.e:

const i = n % arr.length

Because we are wanting to use negative numbers too, we need to adapt our modulo operation slightly (using this answer) as JavaScript's version of the modulo is slightly different to other implementations when it comes to dealing with negative numbers.

so..

const i = ((n % arr.length) + arr.length) % arr.length

Then it's a simple case of using spread operators from ES6 in order to stitch together the new array from the end/start of the old array:

return [...arr.slice(-i), ...arr.slice(0, arr.length - i)]

This results in a function that passes all the OPs tests:

const rotate = (arr, n) => {

  const i = ((n % arr.length) + arr.length) % arr.length

  if (!i) return arr

  return [...arr.slice(-i), ...arr.slice(0, arr.length - i)]

}

const data = [1, 2, 3, 4, 5]

console.log(rotate(data, 1)) // => [5, 1, 2, 3, 4]
console.log(rotate(data, 2)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, 3)) // => [3, 4, 5, 1, 2]
console.log(rotate(data, 4)) // => [2, 3, 4, 5, 1]
console.log(rotate(data, 5)) // => [1, 2, 3, 4, 5]

console.log(rotate(data, 0)) // => [1, 2, 3, 4, 5]

console.log(rotate(data, -1)) // => [2, 3, 4, 5, 1]
console.log(rotate(data, -2)) // => [3, 4, 5, 1, 2]
console.log(rotate(data, -3)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, -4)) // => [5, 1, 2, 3, 4]
console.log(rotate(data, -5)) // => [1, 2, 3, 4, 5]

console.log(rotate(data, 7)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, 11)) // => [5, 1, 2, 3, 4]
console.log(rotate(data, 12478)) // => [3, 4, 5, 1, 2]

Here's the TypeScript version:

const rotate = <T,>(arr: T[], n: number): T[] => {

  const i = ((n % arr.length) + arr.length) % arr.length;

  if (!i) return [...arr]

  return [...arr.slice(-i), ...arr.slice(0, arr.length - i)]

}
shennan
  • 10,798
  • 5
  • 44
  • 79