Manipulación de Arrays en Javascript

15 Feb 2011

Javascript no implementa de forma nativa funciones avanzadas para el manejo de Arrays.

Para solucionar esta carencia, podemos utilizar librerías como jQuery o MooTools que si incorporan métodos interesantes o bien codificar nosotros mismos nuestras propias funciones.

Aquí os dejos algunas de las que utilizo habitualmente: concatenar arrays, mezclar valores de forma aleatoria y eliminar duplicados.

Concatenar Arrays

Con este pequeño código, podemos unir dos arrays en uno solo:

var foo = [ 1, 2, 3 ];
var bar = [ 4, 5, 6 ];
 
Array.prototype.push.apply( foo, bar );
console.log( foo ); //[ 1, 2, 3, 4, 5, 6]

Mezclar aleatoriamente los valores de un Array (Shuffle)

Si queremos reordenar los elementos de un Array de forma aleatoria, esta función es perfecta:

function shuffle( myArr ){
  return myArr.sort( function() Math.random() - 0.5 );
}
var foo = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ];
 
console.log( shuffle( foo ) ); //[ 2, 3, 1, 4, 8, 5, 6, 7, 9, 0 ]
Actualización

A raíz de los comentarios de @genezeta y @joseanpg, tengo que admitir que el algoritmo de ordenación anterior no está equilibrado. Y de eso trata exactamente el artículo de Gonzalo en TinselCity, Ordenación aleatoria en Javascript. Como demuestra el autor, en secuencias largas, las posiciones de los números tienden a repetirse, por lo que mejor implementamos un algoritmo más equilibrado como puede ser el Fisher-Yates:

Array.prototype.shuffle = function() {
    for ( var i = this.length-1; i > 0; i-- ) {
        var j = Math.floor( i * Math.random() );
        var tmp = this[ j ];
        this[ j ] = this[ i ];
        this[ i ] = tmp;
    }
    return this;
}
var foo = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ];
 
console.log( foo.shuffle() ); //[5, 4, 9, 6, 7, 3, 8, 2, 0, 1]

Con esta aproximación, la aleatoriedad conseguida es mayor para las largas secuencias y, por tanto, más robustas. Gracias chicos!

Eliminar duplicados (Unique Array)

Si lo que necesitamos es eliminar los valores duplicados, solo tenemos que aplicar la siguiente función:

function uniqueArray( myArr ) {
  var r = [];
  o : for( var i = 0, n = arr.length; i < n; i++ ){
    for( var x = 0, y = r.length; x < y; x++ ){
      if( r[ x ] == myArr[ i ] ){
        continue o;
      }
    }
    if( !!myArr[ i ] ) r[ r.length ] = myArr[ i ];
  }
  return r;
}
 
var foo = [ 'foo', 'bar', 1, 2, 3, 'bar', 'foo', 5, 3, 2 ];
console.log( uniqueArray( foo ) ); //["foo", "bar", 1, 2, 3, 5]

Espero que estas funciones os resulten interesantes y, sobre todo, prácticas.

Más:

{10} Comentarios.

  1. joseanpg

    Hola de nuevo Carlos. Creo que hay una errata en shuffle: faltan las llaves del camparador y el return está mal colocador, ¿debería ser así?

    function shuffle( myArr ){
       myArr.sort( function() {return Math.random() - 0.5;} );
    }
    
    • Carlos Benítez

      Hola;
      la idea era hacer una función lo más corta posible.
      He utilizado muchos shortcuts y quizá no sea muy legible, pero es correcta.
      ( Para los más puristas, indicar que JSLint no la valida ).

      Su desarrollo completo (y validado) sería:

      function shuffle( myArr ){
        var tmp = function(){ 
          return Math.random() - 0.5;
        };    
        return myArr.sort( tmp );
      }
      

      Un saludo.

  2. joseanpg

    Carlos esa forma de definir funciones no es estandar. Se admite en JS 1.8 de Mozilla (ver Expression closures ) pero no es compatible con ECMAScript 5. Un Firefox actual lo mismo lo digiere pero, por ejemplo, Chromium da un SyntaxError.

    • Carlos Benítez

      Efectivamente no es estándar, por eso he puesto el desarrollo anterior para los más puristas.
      La función ha sido testeada con JSFiddler y la utilizo a menudo en proyectos reales, pero es cierto que no la he probado directamente con Chromium.

      Gracias por el aviso!
      Le echaré un vistazo 🙂

  3. joseanpg

    Por otra parte sobre hay un par de aspectos que comentar sobre esa implementación de shuffle:

    El comparador aleatorio no es una función estable y no cumple con los requisitos especificados para Array.prototype.sort. Quedaremos por tanto en manos de la implementación con lo que eso implica.

    Utilzar un algoritmo de ordenación es menos eficiente que el algortimo clásico de Durstenfeld, algoritmo de orden O(n). Ningún algoritmo de ordenación tiene ese promedio.

  4. gnz/vnk

    Mucho ciudado si pretendes que la mezcla sea realmente aleatoria. http://tinselcity.net/ordenacion-aleatoria-array-javascript

  5. joseanpg

    Aquí te dejo una posible implementación:

    Array.prototype.shuffle = function() { //Es un "mutador"
        for (var i = this.length-1; i > 0; i--) {
            var j = Math.floor(i*Math.random());
            var tmp = this[j];
            this[j] = this[i];
            this[i] = tmp;
        }
        return this;
    }
    
    Array.prototype.makeShuffledClone = function() {//Crea un nuevo array
        return this.slice().shuffleMutator();
    }
    
    • Carlos Benítez

      Gran aporte!

      Te corrijo el método makeShuffledClone:

      Array.prototype.makeShuffledClone = function() {
          return this.slice().shuffle();
      }
      

      Una buena aproximación al Fisher–Yates shuffle.

      Gracias de nuevo joseanpg! 🙂

  6. David Romaní

    Os paso otro de simple pero efectivo para intercambiar la posición de elementos:
    Array.prototype.swap = function (x,y) {
    var b = this[x];
    this[x] = this[y];
    this[y] = b;
    return this;
    };

  7. Lenin

    Hola, un pequeño error en el codigo que elimina duplicados.

    o : for( var i = 0, n = arr.length; i < n; i++ ){

    o : for( var i = 0, n = myArr.length; i < n; i++ ){

    Alguno sabe como podria eliminar valores duplicados en un array bidimensional.

    Por ejemplo:

    [[46, 3], [22, 4], [48, 3], [78, 3], [54, 1], [20, 4], [75, 2], [35, 1], [66, 1], [69, 3], [24, 4], [18, 2], [50, 2], [37, 3], [17, 5], [38, 2], [56, 1], [32, 2], [52, 3], [22, 4], [17, 5], [46, 3], [45, 2], [23, 2], [59, 2], [49, 2], [16, 3], [33, 1], [29, 1], [24, 4], [22, 4], [42, 3], [48, 3], [26, 1], [25, 1], [61, 3], [78, 3], [45, 2], [34, 5], [49, 2], [70, 2], [51, 1], [73, 2], [31, 1], [37, 3], [34, 5], [16, 3], [22, 4], [55, 3], [58, 2], [55, 3], [74, 3], [34, 5], [74, 3], [42, 3], [20, 4], [70, 2], [73, 2], [28, 1], [59, 2], [19, 1], [52, 3], [17, 5], [17, 5], [65, 3], [69, 3], [32, 2], [77, 2], [23, 2], [34, 5], [21, 3], [67, 1], [16, 3], [78, 3], [38, 2], [80, 2], [20, 4], [74, 3], [44, 1], [46, 3], [77, 2], [47, 1], [21, 3], [61, 3], [24, 4], [79, 2], [71, 1], [55, 3], [61, 3], [42, 3], [37, 3], [20, 4], [43, 1], [79, 2], [34, 5], [65, 3], [75, 2], [15, 1], [48, 3], [80, 2], [50, 2], [24, 4], [57, 3], [52, 3], [72, 1], [21, 3], [69, 3], [17, 5], [30, 1], [18, 2], [57, 3], [65, 3], [57, 3], [58, 2]]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *