Después de consultar expertos en la materia, programadores de varias áreas y maestros dimos con la solución al problema y la compartimos en este post.
Solución:
El algoritmo aleatorio imparcial de facto es Fisher-Yates (también conocido como Knuth) Shuffle.
Ver https://github.com/coolaj86/knuth-shuffle
Puede ver una gran visualización aquí (y la publicación original vinculada a esto)
function shuffle(array)
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex)
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
return array;
// Used like so
var arr = [2, 11, 37, 42];
shuffle(arr);
console.log(arr);
Algo más de información sobre el algoritmo utilizado.
Aquí hay una implementación de JavaScript de Durstenfeld shuffle, una versión optimizada de Fisher-Yates:
/* Randomize array in-place using Durstenfeld shuffle algorithm */
function shuffleArray(array)
for (var i = array.length - 1; i > 0; i--)
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
Escoge un elemento aleatorio para cada original array elemento, y lo excluye del próximo sorteo, como elegir al azar de una baraja de cartas.
Esta exclusión inteligente intercambia el elemento seleccionado con el actual, luego selecciona el siguiente elemento aleatorio del resto, retrocediendo para una eficiencia óptima, asegurando que la selección aleatoria se simplifique (siempre puede comenzar en 0) y, por lo tanto, omitir el elemento final.
El tiempo de ejecución del algoritmo es O(n)
. Nota que la reproducción aleatoria se realiza en el lugar, por lo que si no desea modificar el original arrayprimero haz una copia con .slice(0)
.
EDITAR: Actualización a ES6 / ECMAScript 2015
El nuevo ES6 nos permite asignar dos variables a la vez. Esto es especialmente útil cuando queremos intercambiar los valores de dos variables, ya que podemos hacerlo en una línea de código. Aquí hay una forma más corta de la misma función, usando esta característica.
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
¡Advertencia!
El uso de este algoritmo es no recomendadoporque es ineficiente y fuertemente sesgado; ver comentarios. Se deja aquí para referencia futura, porque la idea no es tan rara.
[1,2,3,4,5,6].sort( () => .5 - Math.random() );
Este https://javascript.info/array-métodos#shuffle-an-array tutorial explica las diferencias directamente.