Я задавался вопросом, что самый эффективный путь состоял в том, чтобы повернуть массив 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 там с массивом, вращаются встроенный? (Все еще отвеченный любым)
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;
};
})();
В комментариях Жан поднял вопрос о том, что код не поддерживает перегрузку push()
и splice()
. Я не думаю, что это действительно полезно (см. комментарии), но быстрым решением (хотя и немного хакерским) было бы замена строки
push.apply(this, splice.call(this, 0, count));
на эту:
(this.push || push).apply(this, (this.splice || splice).call(this, 0, count));
Использование unshift()
вместо push()
в Опера 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;
};
})();
Если ваш массив будет большим и/или вы будете много вращаться, вы можете рассмотреть возможность использования связанного списка вместо массива.
.Как насчет инкремента счетчика, а затем получения остатка деления на длину массива, чтобы попасть туда, где вы должны быть.
var i = 0;
while (true);
{
var position = i % months.length;
alert(months[position]);
++i;
}
Синтаксис языка в стороне от этого должен работать нормально.
Наверное, я бы сделал что-нибудь вроде этого:
Array.prototype.rotate = function(n) {
return this.slice(n, this.length).concat(this.slice(0, n));
}
Edit Here's a mutator version:
Array.prototype.rotate = function(n) {
while (this.length && n < 0) n += this.length;
this.push.apply(this, this.splice(0, n));
return this;
}