Tengo una matriz como esta:
var arr1 = ["a", "b", "c", "d"];
¿Cómo puedo aleatorizarlo / barajarlo?
javascript
arrays
random
shuffle
Haga clic en Upvote
fuente
fuente
Respuestas:
El algoritmo de shuffle imparcial de facto es el Shuffle Fisher-Yates (también conocido como Knuth).
Ver https://github.com/coolaj86/knuth-shuffle
Puedes ver una gran visualización aquí (y la publicación original vinculada a esto )
Más información sobre el algoritmo utilizado.
fuente
i--
no--i
. Además, la pruebaif (i==0)...
es superflua, ya que sii == 0
el tiempo nunca será entró en bucle. La llamada aMath.floor
se puede hacer más rápido usando...| 0
. Se pueden eliminar tempi o tempj y el valor se puede asignar directamente a myArray [i] o j según corresponda.0 !== currentIndex
).Aquí hay una implementación de JavaScript del Durstenfeld shuffle , una versión optimizada de Fisher-Yates:
Elige un elemento aleatorio para cada elemento de matriz original y lo excluye del siguiente sorteo, como elegir aleatoriamente de una baraja de cartas.
Esta inteligente exclusión intercambia el elemento seleccionado con el actual, luego selecciona el siguiente elemento aleatorio del resto, haciendo un bucle hacia atrás para una eficiencia óptima, asegurando que la selección aleatoria se simplifica (siempre puede comenzar en 0) y, por lo tanto, omite el elemento final.
El tiempo de ejecución del algoritmo es
O(n)
. Tenga en cuenta que la reproducción aleatoria se realiza en el lugar, por lo que si no desea modificar la matriz original, primero haga una copia con ella.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, utilizando esta función.
fuente
return array
ya que JavaScript pasa las matrices por referencia cuando se usa como argumentos de función. Supongo que esto es para ahorrar espacio en la pila, pero es una pequeña característica interesante. Al realizar la reproducción aleatoria en la matriz, se barajará la matriz original.Math.random() should not be multiplied with the loop counter + 1, but with
array.lengt () `. Ver ¿ Generar números enteros aleatorios en JavaScript en un rango específico? para una explicación muy completafuente
Uno podría (o debería) usarlo como un prototipo de Array:
De ChristopheD:
fuente
for...in
bucles para iterar sobre matrices.Puede hacerlo fácilmente con el mapa y ordenar:
Puede barajar matrices polimórficas, y el orden es tan aleatorio como Math.random, que es lo suficientemente bueno para la mayoría de los propósitos.
Dado que los elementos se ordenan según claves consistentes que no se regeneran en cada iteración, y cada comparación se extrae de la misma distribución, se cancela cualquier no aleatoriedad en la distribución de Math.random.
Velocidad
La complejidad temporal es O (N log N), igual que la ordenación rápida. La complejidad del espacio es O (N). Esto no es tan eficiente como un shuffle de Fischer Yates pero, en mi opinión, el código es significativamente más corto y más funcional. Si tiene una gran variedad, sin duda debería usar Fischer Yates. Si tiene una pequeña matriz con unos cientos de elementos, puede hacer esto.
fuente
Use la biblioteca underscore.js. El método
_.shuffle()
es bueno para este caso. Aquí hay un ejemplo con el método:fuente
shuffle
función.¡NUEVO!
Algoritmo aleatorio Fisher-Yates más corto y probablemente * más rápido
tamaño del script (con fy como nombre de la función): 90bytes
MANIFESTACIÓN http://jsfiddle.net/vvpoma8w/
* más rápido probablemente en todos los navegadores, excepto Chrome.
Si tiene alguna pregunta solo pregunte.
EDITAR
si es mas rapido
ACTUACIÓN: http://jsperf.com/fyshuffle
utilizando las funciones más votadas.
EDITAR Hubo un cálculo en exceso (no necesita --c + 1) y nadie se dio cuenta
más corto (4bytes) y más rápido (¡pruébalo!).
El almacenamiento en caché en otro lugar
var rnd=Math.random
y luego el usornd()
también aumentaría ligeramente el rendimiento en grandes matrices.http://jsfiddle.net/vvpoma8w/2/
Versión legible (use la versión original. Esto es más lento, los vars son inútiles, como los cierres & ";", el código en sí también es más corto ... tal vez lea esto Cómo 'minificar' el código Javascript , por cierto no puede comprima el siguiente código en un minifier javascript como el anterior).
fuente
fy
yshuffle prototype
, me salefy
constantemente en la parte inferior en Chrome 37 en OS X 10.9.5 (81% más lento ~ 20k ops en comparación con ~ 100k) y Safari 7.1 es hasta ~ 8% más lento. YMMV, pero no siempre es más rápido. jsperf.com/fyshuffle/3Editar: esta respuesta es incorrecta
Ver comentarios y https://stackoverflow.com/a/18650169/28234 . Se deja aquí como referencia porque la idea no es rara.
Una forma muy simple para arreglos pequeños es simplemente esto:
Probablemente no sea muy eficiente, pero para arreglos pequeños esto funciona bien. Aquí hay un ejemplo para que pueda ver cuán aleatorio (o no) es, y si se ajusta a su caso de uso o no.
fuente
Fiable, eficiente, corto
Algunas soluciones en esta página no son confiables (solo aleatorizan parcialmente la matriz). Otras soluciones son significativamente menos eficientes. Con
testShuffleArrayFun
(ver más abajo) podemos probar las funciones de combinación aleatoria de la matriz en cuanto a confiabilidad y rendimiento. Las siguientes soluciones son: confiables, eficientes y cortas (usando la sintaxis ES6)[Las pruebas de comparación se realizaron usando
testShuffleArrayFun
otras soluciones, en Google Chrome]Mezclar matriz en su lugar
ES6 puro, iterativo
Prueba de confiabilidad y rendimiento
Como puede ver en esta página, se han ofrecido soluciones incorrectas aquí en el pasado. Escribí y he usado la siguiente función para probar cualquier función aleatoria de matriz pura (sin efectos secundarios).
Otras soluciones
Otras soluciones solo por diversión.
ES6 puro, recursivo
ES6 Pure usando array.map
ES6 Pure usando array.reduce
fuente
[array[i], array[rand]]=[array[rand], array[i]]
? Tal vez puedas describir cómo funciona eso. ¿Por qué eliges iterar hacia abajo?Agregando a @Laurens Holsts respuesta. Esto es 50% comprimido.
fuente
var b =
en un bucle en lugar de declarar b fuera del bucle y asignarlob =
en un bucle?Editar: esta respuesta es incorrecta
Ver https://stackoverflow.com/a/18650169/28234 . Se deja aquí como referencia porque la idea no es rara.
https://javascript.info/task/shuffle
fuente
Con ES2015 puedes usar este:
Uso:
fuente
n >>> 0
lugar de~~n
. Los índices de matriz pueden ser superiores a 2³¹-1.Encontré esta variante colgando en las respuestas "eliminado por el autor" en un duplicado de esta pregunta. A diferencia de algunas de las otras respuestas que ya tienen muchos votos positivos, esto es:
shuffled
nombre en lugar deshuffle
)Aquí hay un jsfiddle que lo muestra en uso .
fuente
[1,2,3,4,5,6].sort(function() { return .5 - Math.random(); });
- no da un orden aleatorio, y si lo usa puede terminar avergonzado: robweir.com/blog/2010/02/microsoft-random-browser-ballot.html.sort(function(a,b){ return a[0] - b[0]; })
si desea que el ordenamiento compare valores numéricamente. El.sort()
comparador predeterminado es lexicográfico, lo que significa que se considerará10
menor que2
ya que1
es menor que2
.Math.random()
produce. (es decir, el orden lexicográfico es el mismo que el orden numérico cuando se trata de números del 0 (inclusive) al 1 (exclusivo))fuente
fuente
Puedes hacerlo fácilmente con:
Consulte las matrices de ordenación de JavaScript
fuente
Una solución recursiva:
fuente
Fisher-Yates baraja en javascript. Estoy publicando esto aquí porque el uso de dos funciones de utilidad (swap y randInt) aclara el algoritmo en comparación con las otras respuestas aquí.
fuente
En primer lugar, eche un vistazo aquí para ver una excelente comparación visual de los diferentes métodos de clasificación en JavaScript.
En segundo lugar, si echas un vistazo rápido al enlace de arriba, verás que el
random order
tipo parece funcionar relativamente bien en comparación con los otros métodos, a la vez que es extremadamente fácil y rápido de implementar como se muestra a continuación:Editar : como señaló @gregers, la función de comparación se llama con valores en lugar de índices, por lo que debe usarla
indexOf
. Tenga en cuenta que este cambio hace que el código sea menos adecuado para matrices más grandes, ya que seindexOf
ejecuta en tiempo O (n).fuente
Array.prototype.sort
pasa en dos valores comoa
yb
, no el índice. Entonces este código no funciona.una función aleatoria que no cambia la matriz fuente
Actualización : Aquí estoy sugiriendo un algoritmo relativamente simple (no desde una perspectiva de complejidad ) y corto que funcionará bien con matrices de pequeño tamaño, pero definitivamente va a costar mucho más que el algoritmo clásico de Durstenfeld cuando se trata de matrices enormes. Puede encontrar el Durstenfeld en una de las principales respuestas a esta pregunta.
Respuesta original:
Si no desea que su función aleatoria mute la matriz fuente , puede copiarla en una variable local y luego hacer el resto con una simple lógica aleatoria .
Lógica aleatoria : seleccione un índice aleatorio, luego agregue el elemento correspondiente a la matriz de resultados y elimínelo de la copia de la matriz de origen . Repita esta acción hasta que la matriz fuente se vacíe .
Y si realmente lo quieres corto, aquí está lo lejos que podría llegar:
fuente
splice
siendo una forma terriblemente ineficiente de hacer lo que llamaron "ponchar". Si no desea mutar la matriz original, simplemente cópiela y luego baraje esa copia en su lugar utilizando la variante de Durstenfeld mucho más eficiente.splice
método para crear una copia de este modo:source = array.slice();
.Aquí está el más fácil ,
por ejemplo, puedes consultarlo aquí
fuente
Otra implementación más de Fisher-Yates, usando el modo estricto:
fuente
Todas las otras respuestas se basan en Math.random (), que es rápido pero no adecuado para la aleatorización de nivel criptográfico.
El código siguiente está utilizando el bien conocido
Fisher-Yates
algoritmo mientras que la utilizaciónWeb Cryptography API
de nivel criptográfico de asignación al azar .fuente
Solución moderna en línea corta que utiliza las funciones de ES6:
(con fines educativos)
fuente
Una modificación simple de la respuesta de CoolAJ86 que no modifica la matriz original:
fuente
Aunque ya hay una serie de implementaciones recomendadas, creo que podemos hacerlo más corto y fácil usando forEach loop, por lo que no debemos preocuparnos por calcular la longitud de la matriz y también podemos evitar con seguridad el uso de una variable temporal.
fuente
Solo para tener un dedo en el pastel. Aquí presento una implementación recursiva de Fisher Yates shuffle (creo). Da aleatoriedad uniforme.
Nota: El
~~
(operador de doble tilde) se comporta de hecho comoMath.floor()
para números reales positivos. Solo un atajo es.Editar: El código anterior es O (n ^ 2) debido al empleo de
.splice()
pero podemos eliminar el empalme y la combinación aleatoria en O (n) mediante el truco de intercambio.El problema es que JS no puede cooperar con grandes recursiones. En este caso particular, el tamaño de su matriz está limitado con 3000 ~ 7000, dependiendo del motor de su navegador y algunos hechos desconocidos.
fuente
Aleatorizar matriz
fuente
-1
for n ya que<
no lo<=
la
arrayShuffle
función más cortafuente
Desde un punto de vista teórico, la forma más elegante de hacerlo, en mi humilde opinión, es obtener un único número aleatorio entre 0 y n! -1 y calcular un mapeo uno a uno de
{0, 1, …, n!-1}
todas las permutaciones de(0, 1, 2, …, n-1)
. Siempre que pueda usar un generador (pseudo-) aleatorio lo suficientemente confiable como para obtener dicho número sin ningún sesgo significativo, tendrá suficiente información para lograr lo que desea sin necesidad de varios otros números aleatorios.Al calcular con números flotantes de precisión doble IEEE754, puede esperar que su generador aleatorio proporcione aproximadamente 15 decimales. Como tiene 15! = 1,307,674,368,000 (con 13 dígitos), puede usar las siguientes funciones con matrices que contienen hasta 15 elementos y asumir que no habrá sesgo significativo con matrices que contengan hasta 14 elementos. Si trabaja en un problema de tamaño fijo que requiere calcular muchas veces esta operación aleatoria, puede probar el siguiente código, que puede ser más rápido que otros códigos ya que
Math.random
solo se usa una vez (sin embargo, implica varias operaciones de copia).La siguiente función no se utilizará, pero la doy de todos modos; devuelve el índice de una permutación dada de
(0, 1, 2, …, n-1)
acuerdo con el mapeo uno a uno utilizado en este mensaje (el más natural al enumerar permuciones); Está diseñado para trabajar con hasta 16 elementos:El recíproco de la función anterior (requerido para su propia pregunta) está abajo; está diseñado para trabajar con hasta 16 elementos; devuelve la permutación de orden n de
(0, 1, 2, …, s-1)
:Ahora, lo que quieres simplemente es:
Debería funcionar para hasta 16 elementos con un pequeño sesgo teórico (aunque imperceptible desde un punto de vista práctico); se puede ver como totalmente utilizable para 15 elementos; con matrices que contienen menos de 14 elementos, puede considerar con seguridad que no habrá absolutamente ningún sesgo.
fuente