JavaScript数组rotate()

时间:2009-12-31 12:44:11

标签: javascript arrays rotation

我想知道旋转JavaScript数组的最有效方法是什么。

我提出了这个解决方案,其中正数n将数组向右旋转,向左旋转n-length < n < length):

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

然后可以这样使用:

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

我上面的原始版本有一个缺陷,正如Christoph在下面的评论中指出的那样,正确的版本是(额外的返回允许链接):

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

是否有更紧凑和/或更快的解决方案,可能在JavaScript框架的上下文中? (下面提出的版本没有一个更紧凑或更快)

是否有内置数组旋转的JavaScript框架? (仍然没有人回答)

37 个答案:

答案 0 :(得分:111)

您可以使用push()pop()shift()unshift()方法:

function arrayRotateOne(arr, reverse) {
  if (reverse) arr.unshift(arr.pop());
  else arr.push(arr.shift());
  return arr;
}

用法:

arrayRotate(['h','e','l','l','o']);       // ['e','l','l','o','h'];
arrayRotate(['h','e','l','l','o'], true); // ['o','h','e','l','l'];

如果您需要count参数,请参阅我的其他答案:https://stackoverflow.com/a/33451102

答案 1 :(得分:47)

类型安全的通用版本,它会改变数组:

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

在评论中,Jean提出了一个问题,即代码不支持push()splice()的重载。我认为这不是很有用(见评论),但快速解决方案(虽然有点黑客)将取代线

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

这一个:

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

使用unshift()代替push()几乎是Opera 10的两倍,而FF的差异可以忽略不计;代码:

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

答案 2 :(得分:30)

我可能会这样做:

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

编辑以下是mutator版本:

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

答案 3 :(得分:18)

此功能适用于任何数字(即使数字大于数组长度):

function arrayRotate(arr, count) {
  count -= arr.length * Math.floor(count / arr.length)
  arr.push.apply(arr, arr.splice(0, count))
  return arr
}

示例:

function stringRotate(str, count) {
  return arrayRotate(str.split(''), count).join('')
}
for(let i = -6 ; i <= 6 ; i++) {
  console.log(stringRotate("Hello", i), i)
}

结果:

"oHell", -6
"Hello", -5
"elloH", -4
"lloHe", -3
"loHel", -2
"oHell", -1
"Hello",  0
"elloH",  1
"lloHe",  2
"loHel",  3
"oHell",  4
"Hello",  5
"elloH",  6

答案 4 :(得分:5)

这些答案中有很多看起来过于复杂且难以阅读。 我认为我没有看到任何人使用拼接连接...

function rotateCalendar(){
    var cal=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
    cal=cal.concat(cal.splice(0,new Date().getMonth()));
    console.log(cal);  // return cal;
}

console.log输出(*在5月生成):

["May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr"]

至于紧凑性,我可以提供一些通用的单行功能(不包括console.log |返回部分)。只需在参数中提供数组和目标值。

我将这些功能组合成一个四人卡片游戏程序,其中数组是['N','E','S','W']。如果有人想要复制/粘贴他们的需求,我会将它们分开。为了我的目的,我在游戏的不同阶段(Pinochle)寻找轮到接下来的比赛时使用这些功能。我没有考虑速度测试,所以如果有其他人愿意,请随时告诉我结果。

*注意,功能之间的唯一区别是“+1”。

function rotateToFirst(arr,val){  // val is Trump Declarer's seat, first to play
    arr=arr.concat(arr.splice(0,arr.indexOf(val)));
    console.log(arr); // return arr;
}
function rotateToLast(arr,val){  // val is Dealer's seat, last to bid
    arr=arr.concat(arr.splice(0,arr.indexOf(val)+1));
    console.log(arr); // return arr;
}

组合功能......

function rotateArray(arr,val,pos){
    // set pos to 0 if moving val to first position, or 1 for last position
    arr=arr.concat(arr.splice(0,arr.indexOf(val)+pos));
    return arr;
}
var adjustedArray=rotateArray(['N','E','S','W'],'S',1);

adjustedArray =

W,N,E,S

答案 5 :(得分:3)

try:
  # %tensorflow_version only exists in Colab.
  %tensorflow_version 2.x
except Exception:
  pass

import tensorflow as tf 
print("Tensorflow Version:", tf.__version__)
from __future__ import absolute_import, division, print_function, unicode_literals
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
import numpy as np
# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras
#### Import the Fashion MNIST dataset
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

train_images1 = train_images[:,:,:,np.newaxis]
test_images1 = test_images[:,:,:,np.newaxis]
##Scale these values to a range of 0 to 1 before feeding them to the neural network model
### Normalize pixel values to be between 0 and 1
train_images = train_images / 255.0
test_images = test_images / 255.0
##Create the convolutional base
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28,28,1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.summary()
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
model.summary()
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
###Train the model
##Feed the model
history = model.fit(train_images1, train_labels, epochs=10, 
                    validation_data=(test_images1, test_labels))
###Evaluate the model
plt.plot(history.history['accuracy'], label='train_accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1])
plt.legend(loc='lower right')

test_loss, test_acc = model.evaluate(test_images1,  test_labels, verbose=2)

答案 6 :(得分: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']

在一行代码中:

let rotated = [...arr.slice((length - rotation) % length, length), ...arr.slice(0, (length - rotation) % length)];

答案 7 :(得分:3)

@Christoph,你做了一个干净的代码,但 60%比我找到的那个。查看jsPerf上的结果:http://jsperf.com/js-rotate-array/2 [编辑]好了现在有更多的浏览器,这是不明显的巫婆方法最好的

var rotateArray = function(a, inc) {
    for (var l = a.length, inc = (Math.abs(inc) >= l && (inc %= l), inc < 0 && (inc += l), inc), i, x; inc; inc = (Math.ceil(l / inc) - 1) * inc - l + (l = inc))
    for (i = l; i > inc; x = a[--i], a[i] = a[i - inc], a[i - inc] = x);
    return a;
};

var array = ['a','b','c','d','e','f','g','h','i'];

console.log(array);
console.log(rotateArray(array.slice(), -1)); // Clone array with slice() to keep original

答案 8 :(得分:3)

请参阅http://jsperf.com/js-rotate-array/8

function reverse(a, from, to) {
  --from;
  while (++from < --to) {
    var tmp = a[from];
    a[from] = a[to];
    a[to] = tmp;
  }
}

function rotate(a, from, to, k) {
  var n = to - from;
  k = (k % n + n) % n;
  if (k > 0) {
    reverse(a, from, from + k);
    reverse(a, from + k, to);
    reverse(a, from, to);
  }
}

答案 9 :(得分:2)

这是一种在数组中移动项目的简单方法:

function rotate(array, stepsToShift) {

    for (var i = 0; i < stepsToShift; i++) {
        array.unshift(array.pop());
    }

    return array;
}

答案 10 :(得分:2)

2021 年 2 月更新

一个单行函数来执行数组元素的向右旋转向左旋转

向左旋转

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

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]

答案 11 :(得分:2)

此函数比小型阵列的接受答案快一点,但对于大型阵列来说要快得多。此函数还允许任意数量的旋转大于数组的长度,这是原始函数的限制。

最后,接受的答案按照描述的相反方向旋转。

FBSDKGraphRequest(graphPath: "/me/friends", parameters: nil).start(completionHandler: { (connection, user, requestError) -> Void in
        let userData = user as! NSDictionary
        let friends = userData["data"] as? String

        if requestError != nil {
            print(requestError)
            return
        }

        print(friends) // prints nil
})

功能等同物(似乎也有一些性能优势):

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

您可以查看performance breakdown here.

答案 12 :(得分:2)

接受的答案有一个缺陷,即无法处理大于调用堆栈大小的数组,这取决于会话但应该大约100~300K项。例如,在我尝试过的当前Chrome会话中,它是250891.在许多情况下,您甚至可能不知道阵列可能会动态增长到什么大小。所以这是一个严重的问题。

为了克服这个限制,我想一个有趣的方法是利用Array.prototype.map()并通过以循环方式重新排列索引来映射元素。此方法采用一个整数参数。如果这个论点是积极的,那么它将在增加指数时旋转,如果在减少指数方向上则为负。这只有O(n)的时间复杂度,并且会在没有任何问题的情况下处理数百万个项目时返回一个新的数组,而不会改变它所调用的数组。让我们看看它是如何工作的;

Array.prototype.rotate = function(n) {
var len = this.length;
return !(n % len) ? this
                  : n > 0 ? this.map((e,i,a) => a[(i + n) % len])
                          : this.map((e,i,a) => a[(len - (len - i - n) % len) % len]);
};
var a = [1,2,3,4,5,6,7,8,9],
    b = a.rotate(2);
console.log(JSON.stringify(b));
    b = a.rotate(-1);
console.log(JSON.stringify(b));

实际上,在我受到如下两个问题的批评后,

  1. 不需要有条件的正面或负面输入,因为它显示违反了DRY。你可以用一张地图做这个,因为每个负面的n都有一个正面的等价物(完全正确..)
  2. 数组函数应该更改当前数组或创建一个新数组,您的函数可以根据是否需要移位来完成(完全正确..)
  3. 我决定修改代码如下;

    Array.prototype.rotate = function(n) {
    var len = this.length;
    return !(n % len) ? this.slice()
                      : this.map((e,i,a) => a[(i + (len + n % len)) % len]);
    };
    var a = [1,2,3,4,5,6,7,8,9],
        b = a.rotate(10);
    console.log(JSON.stringify(b));
        b = a.rotate(-10);
    console.log(JSON.stringify(b));

    然后再说;当然,像Array.prototype.map()这样的JS函子与它们在普通JS中编码的等价物相比较慢。为了获得超过100%的性能提升,如果我需要在生产代码中旋转数组(如我在Array.prototype.rotate()尝试中使用的那个数组),那么我可能会选择String.prototype.diff()。 p>

    Array.prototype.rotate = function(n){
      var len = this.length,
          res = new Array(this.length);
      if (n % len === 0) return this.slice();
      else for (var i = 0; i < len; i++) res[i] = this[(i + (len + n % len)) % len];
      return res;
    };
    

答案 13 :(得分:2)

当我找不到一个现成的片段来开始“今天”的日期列表时,我就这样做了(不太通用,可能远不如上面的例子那么精致,但做了这个工作):

//returns 7 day names with today first
function startday() {
    const days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
    let today = new Date();
    let start = today.getDay(); //gets day number
    if (start == 0) { //if Sunday, days are in order
        return days
    }
    else { //if not Sunday, start days with today
        return days.slice(start).concat(days.slice(0,start))
    }
}

感谢一个比我更好的程序员的一点点重构,它比我最初的尝试短了一两行,但欢迎任何关于效率的进一步评论。

答案 14 :(得分:1)

使用ES6的价差作为不可变的示例...

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

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

虽然可能不是最有效的,但是很简洁。

答案 15 :(得分:1)

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

答案 16 :(得分:1)

具有切片和解构功能的简便解决方案:

const rotate = (arr, count) => {
	if (count === 0) return arr;
  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]

答案 17 :(得分:0)

为了将数组向左旋转 'd' 个位置,我们可以使用 unshift() 和 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);

对于黑客等级,解决DS左右旋转问题的解决方案(javascript,java)查看我下面的文章

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

答案 18 :(得分:0)

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)

答案 19 :(得分:0)

我这样做没有任何帮助库

if ($request->hasFile('image')) {
            $image = $request->file('image'); //request the file
            $fileName = md5($image . microtime()) . '.' . $image->getClientOriginalExtension(); //use md5 for security reasons and get the extension.
            $image->storeAs('', $fileName, 'public'); //store the file in the public folder disk.
        } 
        
         if ($request->wantsJson()) {
             return response([], 204);
        }

答案 20 :(得分:0)

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

答案 21 :(得分:0)

使用以下-

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

d的旋转次数
最佳解决方案,无需使用爆破推力的蛮力技术 O(1)时间复杂度

答案 22 :(得分:0)

具有es6语法

Mutex

答案 23 :(得分:0)

不要使用 concatsplice 或其他任何东西。使用 .mapwhile 循环可以简单有效地向左或向右旋转。这个想法是迭代原始数组的长度。在每次迭代时,更新要添加到新旋转数组的旋转中下一个值的索引。该解决方案的时间复杂度为 O(n) --- 在两个示例中都只有一个循环。

地图:

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]

虽然:

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

spliceconcat 方法是 O(n) 操作;前者删除然后返回一个“拼接”值数组,后者返回一个包含合并数组值的新数组。所以,如果你同时使用它们,你做了太多的工作:O(n) * 2 以及两个新复制的数组。坦率地说,使用简单的 while 循环可以更容易地了解发生的事情的逻辑。

答案 24 :(得分:0)

使用循环。这是步骤

  1. 将数组的第一个元素存储为临时变量。
  2. 然后从左向右交换。
  3. 然后将temp变量分配给数组的最后一个元素。
  4. 重复这些步骤以获取转数。

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

答案 25 :(得分:0)

JS中的

Array具有以下内置方法,可以很容易地旋转数组,显然这些方法本质上是不可变的

  • push:将该项插入数组的末尾。
  • pop:从数组末尾删除项目。
  • unshift:将项目插入数组的开头。
  • shift:从数组的开头删除该项。

以下解决方案(ES6)有两个参数,需要旋转数组,而n则应旋转数组的次数。

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

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

它可以添加到Array.prototype中,并且可以在您的应用程序中全部使用

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]

答案 26 :(得分:0)

**使用最新版本的JS,我们可以轻松构建它**

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

这里移动:转数,一个可以传递随机数的数组

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

答案 27 :(得分:0)

本机的,快速的,小巧的,语义化的,可以在旧引擎上使用,并且“易变”。

function rotateArray(offset, array) {
    offset = -(offset % array.length) | 0 // ensure int
    return array.slice(offset).concat(
        array.slice(0, offset)
    )
}

答案 28 :(得分:0)

我正在分享我的解决方案,该解决方案用于在旋转木马上旋转。 当数组的大小小于$('#my-target-ol').('/the/page/to/load.html #my-included-list li') 时,它可能会中断,但是您可以添加额外的条件以在数组很小时停止旋转,或者也可以将主数组并置* displayCount次。

displayCount

答案 29 :(得分:0)

非变异解

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

具有突变

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

答案 30 :(得分:0)

我不确定这是否是最有效的方法,但是我喜欢它的读取方式,因为在生产环境中对它进行了测试,它的速度足以应付大多数大型任务...

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

答案 31 :(得分:0)

修改:: 嘿,事实证明有太多的迭代发生。没有循环,没有分支。

对于任何大小的n,仍然适用于右旋转的负n和左旋转的正n, 无变异

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

这是giggles的代码高尔夫版本

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

<强> EDIT1 :: * 无分支,无突变的实现。

嘿,原来我有一个我不需要它的分支。这是一个有效的解决方案。 负数=右旋转|数字| 正数=左旋数字

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

等式((n%l) + l) % l精确映射任意大的n值的正数和负数

<强> ORIGINAL

左右旋转。向左旋转,显示正n,向右旋转,显示为负n

适用于n的大量输入。

无突变模式。这些答案中有太多突变。

此外,操作少于大多数答案。没有流行,没有推动,没有拼接,没有转变。

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

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

说明:

将A的每个索引映射到索引偏移处的值。在这种情况下

offset = num

如果offset < 0然后offset + index + positive length of A将指向反向偏移量。

如果offset > 0 and offset < length of A,则只需将当前索引映射到A的偏移索引。

否则,以模数偏移量和长度来映射数组范围内的偏移量。

以实例offset = 4offset = -4为例。

对于每个索引offset = -4A = [1,2,3,4,5]offset + index会使幅度(或Math.abs(offset))变小。

让我们首先解释负n的索引的计算。 A[(((n % A.length) + A.length) % A.length)+0]并被吓倒了。 不要。我花了3分钟在Repl中解决问题。

  1. 我们知道n是否定的,因为案例为n < 0。如果数字大于数组的范围,n % A.length会将其映射到范围内。
  2. n + A.length将该号码添加到A.length以抵消正确的号码 量。
  3. 我们知道n是否定的,因为案例为n < 0n + A.length将该数字添加到A.length以抵消正确的金额。
  4. 接下来使用模数将其映射到A的长度范围。第二个模型是将计算结果映射到可索引范围

    的必要条件

    enter image description here

  5. 第一个指数:-4 + 0 = -4。 A.length = 5. A.length - 4 = 1. A 2是2.将索引0映射到2. [2,... ]

  6. 下一个索引,-4 + 1 = -3。 5 + -3 = 2. 2为3.将索引1映射到3. [2,3... ]
  7. 同样的过程适用于offset = 4。 对于每个索引offset = -4A = [1,2,3,4,5]offset + index会使幅度更大。

    1. 4 + 0 = 0。将A [0]映射到A [4]处的值。 [5...]
    2. 4 + 1 = 5,5在编制索引时超出范围,因此将A 2映射到 值为5 / 5的余数,即0. 2 =的值为 A [0]。 [5,1...]
    3. 重复。

答案 32 :(得分:0)

我来晚了但是我有一块砖来补充这些好的答案。 我被要求编写这样的函数,我首先做了:

Array.prototype.rotate = function(n)
{
    for (var i = 0; i < n; i++)
    {
        this.push(this.shift());
    }
    return this;
}

但是当n很大时,效率似乎低于跟随:

Array.prototype.rotate = function(n)
{
    var l = this.length;// Caching array length before map loop.

    return this.map(function(num, index) {
        return this[(index + n) % l]
    });
}

答案 33 :(得分:0)

@molokoloco我需要一个可以配置为在一个方向上旋转的功能 - 对于向前是true而对于向后是false。我创建了一个片段,它接受一个方向,一个计数器和一个数组,并输出一个对象,其中计数器在适当的方向上递增,以及先前,当前和下一个值。它不会修改原始数组。

我还针对你的片段进行了计时,虽然速度并不快,但它比你比较的更快 - 比http://jsperf.com/js-rotate-array/7慢了21%。

function directionalRotate(direction, counter, arr) {
  counter = direction ? (counter < arr.length - 1 ? counter + 1 : 0) : (counter > 0 ? counter - 1 : arr.length - 1)
  var currentItem = arr[counter]
  var priorItem = arr[counter - 1] ? arr[counter - 1] : arr[arr.length - 1]
  var nextItem = arr[counter + 1] ? arr[counter + 1] : arr[0]
  return {
    "counter": counter,
    "current": currentItem,
    "prior": priorItem,
    "next": nextItem
  }
}
var direction = true // forward
var counter = 0
var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];

directionalRotate(direction, counter, arr)

答案 34 :(得分:0)

如果你的阵列很大和/或你要旋转很多,你可能要考虑使用链表而不是数组。

答案 35 :(得分:0)

如何递增计数器,然后通过数组长度得到除法的余数,以得到你应该在的位置。

var i = 0;
while (true);
{
    var position = i % months.length;
    alert(months[position]);
    ++i;
}
除了语言语法,这应该可以正常工作。

答案 36 :(得分:-2)

不确定效率,但是我会以这种非变异的方式实现:

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