Rotate Array Elements by N Spaces in JavaScript

Implement a function called "rotate" that will take an array and return a new array with the elements rotated by n spaces.

If n is positive, the array should be rotated to the right. If n is negative, then it should be rotated to the left. If n is 0, the array should remain unchanged.

For 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, this function should work with any type of array input, not just numbers:

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]

Additionally, the rotation should wrap around if the index exceeds the length of the array:

For 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]

Answer №1

If you want to achieve this functionality, one way is to use a `while` loop along with `increment` or `decrement` depending on whether the number parameter is positive or negative.

function rotateArray(arr, num) {
  const result = [...arr]

  if (num === 0) {
    return arr
  }

  const isNegative = num < 0
  const lastIdx = result.length - 1
  const toIdx = isNegative ? lastIdx : 0
  const idx = isNegative ? 0 : lastIdx

  while ((isNegative ? num++ : num--) !== 0) {
    result.splice(toIdx, 0, result.splice(idx, 1)[0])
  }

  return result
}


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

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


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

console.log(rotateArray(['a', 'b', 'c'], 1))
console.log(rotateArray([true, true, false], 1))

Answer №2

Shown here is an example that does not mutate the original array and avoids using 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 key concept in this function is determining the starting index based on the arguments provided. This is achieved through the use of the modulo operator to calculate the index relative to the array length and a number that may exceed the array length.

For instance:

const i = n % arr.length

To handle negative numbers as well, a modified modulo operation is used (referencing this answer) because JavaScript's built-in modulo behaves differently with negative numbers compared to other languages.

Therefore..

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

After obtaining the correct index, ES6 spread operators are used to form the new array by combining portions from the end and start of the original array:

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

This approach ensures that the function passes all test cases:

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]

Below is the TypeScript version of the code:

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

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issues with Tailwind functionality within a monorepo setup

I have set up a monorepo architecture using yarn workspaces, with Tailwind CSS being at the root of the project. I have integrated Tailwind utilities into the styles of one of the workspaces that uses React. While Tailwind is functioning properly in the pr ...

Upgrade to the most recent versions of packages using npm

When using npm install --save <package_name>, it typically installs the latest stable version of the package. If you want to specifically install the most recent release, such as Bootstrap v4, you would need to use npm install <a href="/cdn-cgi/l ...

The node.js system automatically restarts an API call when a timeout occurs

Current Setup: I am using a combination of sails.js for the backend API and React for the frontend. The communication between the frontend and backend is handled by the fetch API. Scenario: Within some of my API endpoints, I need to run an external file ...

Tips for targeting an element for focus following a re-render in ReactJS

Within my web application, when a user hits the enter key, they are able to save the current record. A message confirming that the "record has been successfully saved" is then displayed. However, I have noticed that the blinking cursor in one of the input ...

Using Angular's $q service in the run block

I have a scenario where I need to load data from local files using the global loadJSON function (though it's not mandatory, it's recommended). Once the data is loaded from all the documents, I want to print the string 'i ve loaded'. T ...

What is the best way to retrieve information in an autosuggest textbox from a server or database?

I am looking for a way to modify my autosuggest textbox to fetch data from a server instead of a defined array. Can anyone provide guidance on how to achieve this? Here is the code snippet I am currently working with: HTML code- <!doctype html> &l ...

Tips on adding an image using Reactjs

I am currently working in Reactjs with the Next.js framework. I am attempting to upload images using Axios (POST method API) and will be utilizing an "api in PHP". Could someone please guide me on how to achieve this? I have tried the code below, but it&ap ...

"Obtaining a URL that begins with using jQuery: A Step-by-

How can I extract the full URL that starts with http://sin1.g.adnxs.com Here is the code snippet: <div id="testingurl"> <div class="ads98E6LYS20621080"> <!-- This script is dynamically generated --> <iframe src="http://testing ...

Is there a Syntax Issue Preventing the Jquery Accordion from Working in IE7?

I have developed a website that utilizes jquery accordion along with some basic functions to control the accordion via external navigation links. While testing it in different browsers, everything seems to be working fine except for IE7. In IE7, the accord ...

Is Angular automatically assigned to `window.angular` on a global level when it is loaded as a CommonJS module?

When I import Angular 1.4 in my Webpack build entry point module as a CommonJS module using var angular = require("angular");, it somehow ends up being accessible in the global namespace of the browser (as window.angular). Upon examining the source code o ...

Attempting to deactivate the bootstrap-fullscreen-select feature using JavaScript

Currently, I am in the process of developing a Python Flask server to manage a project that I have undertaken. While exploring different options, I came across bootstrap-fullscreen-select which turned out to be exactly what I needed for my control page. H ...

Enable the ability to upload multiple images on a single page using droparea.js

I am currently utilizing droparea js for uploading images. However, I have encountered an issue where if I try to upload an image in one of the upload menus, it ends up changing all four upload menus simultaneously. <div class="col-md-12"> ...

The image is not appearing on mobile devices, but it is displaying correctly on desktop computers

Having trouble with my landing page on compare.comxa.com. When I try to view it on my Android device, only the form shows up and the background image is nowhere to be found. Can anyone help me troubleshoot this issue? Here is the code: ...

Tips for effectively utilizing props in react

Within one of my components named header, there is a button that I want to use to toggle the visibility of the navbar component. To achieve this, I attempted to create a prop in the main component below which houses all the other components including heade ...

`javascript pop up notification will only display one time`

I am currently developing a chrome extension with two different modes. When the user clicks on the icon, a pop-up message should appear to indicate which mode is active. However, I am facing an issue where the message does not always display when the pop- ...

What is the best way to loop through a list of questions and save the answers in an array of user input?

I'm encountering a challenge with iterating through an array of questions to correctly display them on the document. The initial code snippet provided below demonstrates what I aim to accomplish without using prompts. Currently, I have set up an arr ...

Best practice for stopping routing in angular

I am currently working on an angular application that includes guest functionality. This feature allows me to create a guest account for all unauthorized users in the background. I need to pause routing until the guest account is created and then specify a ...

Redirect to a new URL using $routeProvider's resolve feature

Currently, I am in the process of developing an application that includes the following endpoint: .when('/service/:id?', { templateUrl: 'views/service.html', controller: 'ServiceCtrl', resolve: { service: fu ...

Observables and the categorization of response data

Understanding Observables can be a bit tricky for me at times, leading to some confusion. Let's say we are subscribing to getData in order to retrieve JSON data asynchronously: this.getData(id) .subscribe(res => { console.log(data.ite ...

Unforeseen outcomes of JavaScript when using the let and var keywords

In JavaScript, when using the var keyword to declare a variable, the JS engine assigns a default value of "undefined" at creation stage. console.log(message); // undefined var message = "My message"; However, with the let keyword: console.log(message); ...