Rotar los elementos de una matriz en JavaScript

Resuelto Jean Vincent asked hace 14 años • 43 respuestas

Me preguntaba cuál era la forma más eficaz de rotar una matriz de JavaScript.

Se me ocurrió esta solución, donde un positivo nrota la matriz hacia la derecha y un negativo nhacia la izquierda ( -length < n < length):

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

Que luego se puede utilizar de esta manera:

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

Mi versión original anterior tiene un defecto, como lo señala Christoph en los comentarios a continuación, una versión correcta es (el retorno adicional permite encadenar):

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

¿Existe una solución más compacta y/o más rápida, posiblemente en el contexto de un marco de JavaScript? (ninguna de las versiones propuestas a continuación es más compacta o más rápida)

¿Existe algún marco de JavaScript con una rotación de matriz incorporada? (Aún no ha respondido nadie)

Jean Vincent avatar Dec 31 '09 19:12 Jean Vincent
Aceptado

Puede utilizar push(), pop()y shift()métodos unshift():

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

uso:

arrayRotate([1, 2, 3, 4, 5]);       // [2, 3, 4, 5, 1];
arrayRotate([1, 2, 3, 4, 5], true); // [5, 1, 2, 3, 4];

Si necesita countun argumento, vea mi otra respuesta:
https://stackoverflow.com/a/33451102 🖤🧡💚💙💜

Yukulélé avatar Apr 29 '2014 14:04 Yukulélé

Versión genérica con seguridad de tipos que muta la matriz:

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

En los comentarios, Jean planteó el problema de que el código no admite la sobrecarga de push()y splice(). No creo que esto sea realmente útil (ver comentarios), pero una solución rápida (aunque algo así como un truco) sería reemplazar la línea

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

Con este:

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

Usar unshift()en lugar de push()es casi el doble de rápido en Opera 10, mientras que las diferencias en FF fueron insignificantes; el código:

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;
    };
})();
Christoph avatar Dec 31 '2009 13:12 Christoph

Probablemente haría algo como esto:

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

Editar     Aquí hay una versión mutadora:

Array.prototype.rotate = function(n) {
    n = n % this.length;
    while (this.length && n < 0) n += this.length;
    this.push.apply(this, this.splice(0, n));
    return this;
}
Gumbo avatar Dec 31 '2009 12:12 Gumbo

Esta función funciona en ambas direcciones y con cualquier número. (incluso con un número mayor que la longitud de la matriz):

function arrayRotate(arr, count) {
  const len = arr.length
  arr.push(...arr.splice(0, (-count % len + len) % len))
  return arr
}

uso:

for(let i = -6 ; i <= 6 ; i++) {
  console.log(arrayRotate(['🧡', '💚', '💙', '💜', '🖤'], i), i)
}

resultado:

[ '💚', '💙', '💜', '🖤', '🧡' ]    -6
[ '🧡', '💚', '💙', '💜', '🖤' ]    -5
[ '🖤', '🧡', '💚', '💙', '💜' ]    -4
[ '💜', '🖤', '🧡', '💚', '💙' ]    -3
[ '💙', '💜', '🖤', '🧡', '💚' ]    -2
[ '💚', '💙', '💜', '🖤', '🧡' ]    -1
[ '🧡', '💚', '💙', '💜', '🖤' ]    0
[ '🖤', '🧡', '💚', '💙', '💜' ]    1
[ '💜', '🖤', '🧡', '💚', '💙' ]    2
[ '💙', '💜', '🖤', '🧡', '💚' ]    3
[ '💚', '💙', '💜', '🖤', '🧡' ]    4
[ '🧡', '💚', '💙', '💜', '🖤' ]    5
[ '🖤', '🧡', '💚', '💙', '💜' ]    6
Yukulélé avatar Oct 31 '2015 11:10 Yukulélé