在 JavaScript 中旋转数组中的元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1985260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:14:48  来源:igfitidea点击:

Rotate the elements in an array in JavaScript

javascriptarraysrotation

提问by Jean Vincent

I was wondering what was the most efficient way to rotate a JavaScript array.

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

I came up with this solution, where a positive nrotates the array to the right, and a negative nto the left (-length < n < length) :

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

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

Which can then be used this way:

然后可以这样使用:

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

My original version above has a flaw, as pointed out by Christophin the comments bellow, a correct version is (the additional return allows chaining):

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

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

Is there a more compact and/or faster solution, possibly in the context of a JavaScript framework? (none of the proposed versions bellow is either more compact or faster)

是否有更紧凑和/或更快的解决方案,可能在 JavaScript 框架的上下文中?(以下建议的版本都不是更紧凑或更快)

Is there any JavaScript framework out there with an array rotate built-in? (Still not answered by anyone)

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

采纳答案by Christoph

Type-safe, generic version which mutates the array:

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

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

In the comments, Jean raised the issue that the code doesn't support overloading of push()and splice(). I don't think this is really useful (see comments), but a quick solution (somewhat of a hack, though) would be to replace the line

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

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

with this one:

有了这个:

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


Using unshift()instead of push()is nearly twice as fast in Opera 10, whereas the differences in FF were negligible; the code:

在 Opera 10 中使用unshift()代替的push()速度几乎快两倍,而在 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;
    };
})();

回答by Yukulélé

You can use push(), pop(), shift()and unshift()methods:

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

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

usage:

用法:

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

If you need countargument see my other answer: https://stackoverflow.com/a/33451102

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

回答by Gumbo

I would probably do something like this:

我可能会做这样的事情:

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


Edit????Here's a mutator version:

编辑????这是一个mutator版本:

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

回答by Yukulélé

This function works in both way and works with any number (even with number greater than array length):

此函数以两种方式工作并适用于任何数字(即使数字大于数组长度):

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

usage:

用法:

for(let i = -6 ; i <= 6 ; i++) {
  console.log(arrayRotate(["","","","",""], i), i);
}

result:

结果:

[ "", "", "", "", "" ]    -6
[ "", "", "", "", "" ]    -5
[ "", "", "", "", "" ]    -4
[ "", "", "", "", "" ]    -3
[ "", "", "", "", "" ]    -2
[ "", "", "", "", "" ]    -1
[ "", "", "", "", "" ]    0
[ "", "", "", "", "" ]    1
[ "", "", "", "", "" ]    2
[ "", "", "", "", "" ]    3
[ "", "", "", "", "" ]    4
[ "", "", "", "", "" ]    5
[ "", "", "", "", "" ]    6

回答by mickmackusa

So many of these answers seem over-complicated and difficult to read. I don't think I saw anyone using splice with concat...

这些答案中的许多似乎过于复杂且难以阅读。我想我没有看到有人使用带有 concat 的 splice ...

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 outputs (*generated in May):

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

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


As for compactness, I can offer a couple of generic one-liner functions (not counting the console.log | return portion). Just feed it the array and the target value in the arguments.

至于紧凑性,我可以提供几个通用的单行函数(不包括 console.log | return 部分)。只需将数组和参数中的目标值提供给它即可。

I combine these functions into one for a four-player card game program where the array is ['N','E','S','W']. I left them separate in case anyone wants to copy/paste for their needs. For my purposes, I use the functions when seeking whose turn is next to play/act during different phases of the game (Pinochle). I haven't bothered testing for speed, so if someone else wants to, feel free to let me know the results.

我将这些函数合并为一个四人纸牌游戏程序,其中数组为 ['N','E','S','W']。我将它们分开,以防有人想根据需要复制/粘贴。出于我的目的,我在游戏的不同阶段(Pinochle)寻找下一个轮到谁玩/行动时使用这些功能。我没有费心测试速度,所以如果其他人愿意,请随时让我知道结果。

*notice, the only difference between functions is the "+1".

*注意,功能之间的唯一区别是“+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;
}


combination function...

组合功能...

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

回答by Aryeh Harris

Here is a very simple way to shift items in an array:

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

function rotate(array, stepsToShift) {

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

    return array;
}

回答by Dudley Craig

Using ES6's spread for an immutable example ...

使用 ES6 的扩展作为不可变示例......

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

and

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

It's probably not the most efficient though but it's concise.

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

回答by molokoloco

@Christoph, you've done a clean code, but 60% slowestthan this one i found. Look at the result on jsPerf : http://jsperf.com/js-rotate-array/2[Edit] OK now there is more browsers an that not obvious witch methods the best

@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

回答by Vic99999

see http://jsperf.com/js-rotate-array/8

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

回答by Dave Everitt

When I couldn't find a ready-made snippet to start a list of days with 'today', I did it like this (not quite generic, probably far less refined than the above examples, but did the job):

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

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

Thanks to a little refactor by a better programmer than me it's a line or two shorter than my initial attempt, but any further comments on efficiency are welcome.

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