una página llamar librería incluir etiqueta escribir ejemplos documentos desde dentro cómo cuál como codigo cierre cargaríamos apertura abrir javascript arrays shuffle

página - escribir javascript en html



¿Cómo aleatorizar(barajar) una matriz de JavaScript? (30)

Con ES6, 2018

Algunas de las respuestas podrían acortarse con el último ES6.

Shuffle Array en su lugar

function shuffleArray (array){ for (let i = array.length - 1; i > 0; i--) { const rand = Math.floor(Math.random() * (i + 1)); [array[i], array[rand]] = [array[rand], array[i]]; } }

Con ES6 podemos asignar dos valores a la vez. Esto es especialmente útil en la línea 4 anterior, donde se intercambian dos variables en una línea de código.

Deje intacta la matriz original y devuelva una matriz aleatoria

Si desea realizar una función más pura y dejar la matriz original intacta, simplemente puede duplicar la matriz y luego ejecutar el mismo algoritmo.

function getShuffledArray (arr){ let newArr = [...arr] for (let i = newArr.length - 1; i > 0; i--) { const rand = Math.floor(Math.random() * (i + 1)); [newArr[i], newArr[rand]]=[newArr[rand], newArr[i]]; } return newArr; }

Un algoritmo ascendente

El algoritmo a continuación utiliza un bucle ascendente. Es menos intuitivo, pero corto y válido.

function getShuffledArrayAsc (arr){ let newArr = [...arr]; for (let i = 1; i < newArr.length ; i++) { const rand = Math.floor( Math.random() * (i + 1) ); [newArr[i], newArr[rand]] = [newArr[rand], newArr[i]]; } return newArr; }

Comprobación de la fiabilidad de la función de aleatorización

Las funciones anteriores presentan una distribución uniforme cuando se pasan a ''testShuffledArrayFun'' a continuación, tanto en Chrome como en Node. Esto está de acuerdo con lo que esperaríamos de una función de asignación al azar.

function testShuffledArrayFun(getShuffledArrayFun){ // Tests the reliability of the suffleArrayFunction, by callying it 1,000 times and presenting the distribution. const testArr = [0,1,2,3,4]; const countArr = testArr.map( position => // for for each possible position in the shuffledArr, for each possible value, we''ll create a counter. the counter of value 0 in position 0 will be countArr[0][0] testArr.map( value => 0) ) const n = 10000; for (var i=0 ; i<n ; i++){ // We''ll call getShuffledArrayFun for n times. For each shuffledArray we receive we''ll increment the counterArr accordingly. At the end we''ll print the distribution. var shuffledArr = getShuffledArrayFun(testArr); shuffledArr.forEach( (value, key) => {countArr[key][value]++} ); } countArr.forEach( (valueCountArr,key) => { console.log(`Position ${key}:`); valueCountArr.forEach( (count,originalValue) => { console.log(`The Value ${originalValue} appeared ${count*100/n}% `); } ); } ); }

Tengo una matriz como esta:

var arr1 = ["a", "b", "c", "d"];

¿Cómo puedo aleatorizarlo / mezclarlo?


una función aleatoria que no cambia la matriz de origen

Actualización : aquí estoy sugiriendo un algoritmo relativamente simple (no desde la perspectiva de la complejidad ) y corto que funcionará bien con matrices de pequeño tamaño, pero definitivamente 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 mejores respuestas a esta pregunta.

Respuesta original:

Si no desea que su función de reproducción aleatoria mute la matriz de origen , puede copiarla en una variable local, luego hacer el resto con una lógica de combinación aleatoria simple.

function shuffle(array) { var result = [], source = array.concat([]); while (source.length) { let index = Math.floor(Math.random() * source.length); result.push(source[index]); source.splice(index, 1); } return result; }

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 de origen se vacíe .

Y si realmente lo quieres corto, aquí está lo lejos que podría llegar:

function shuffle(array) { var result = [], source = array.concat([]); while (source.length) { let index = Math.floor(Math.random() * source.length); result.push(source.splice(index, 1)[0]); } return result; }


¡NUEVO!

Algoritmo de shuffle de Fisher-Yates más corto y probablemente más rápido

  1. usa mientras ---
  2. en modo bit a piso (números de hasta 10 dígitos decimales (32 bits))
  3. eliminado cierres innecesarios y otras cosas

function fy(a,b,c,d){//array,placeholder,placeholder,placeholder c=a.length;while(c)b=Math.random()*(--c+1)|0,d=a[c],a[c]=a[b],a[b]=d }

Tamaño del script (con fy como nombre de la función): 90bytes

DEMO http://jsfiddle.net/vvpoma8w/

* más rápido probablemente en todos los navegadores excepto en cromo.

Si tiene alguna pregunta solo pregunte.

EDITAR

si es mas rapido

RENDIMIENTO: http://jsperf.com/fyshuffle

Usando las funciones más votadas.

EDITAR Hubo un cálculo en exceso (no es necesario --c + 1) y nadie se dio cuenta

Más corto (4bytes) y más rápido (¡pruébalo!).

function fy(a,b,c,d){//array,placeholder,placeholder,placeholder c=a.length;while(c)b=Math.random()*c--|0,d=a[c],a[c]=a[b],a[b]=d }

Almacenar en caché en otro lugar var rnd=Math.random y luego usar rnd() también aumentaría ligeramente el rendimiento en matrices grandes.

http://jsfiddle.net/vvpoma8w/2/

Versión legible (use la versión original. Esto es más lento, las variables son inútiles, como los cierres y ";", el código en sí también es más corto ... quizás lea esto Cómo ''minificar'' el código Javascript , por cierto no puede comprime el siguiente código en un javascript como el anterior.)

function fisherYates( array ){ var count = array.length, randomnumber, temp; while( count ){ randomnumber = Math.random() * count-- | 0; temp = array[count]; array[count] = array[randomnumber]; array[randomnumber] = temp } }


Añadiendo a la respuesta de @Laurens Holsts. Esto es 50% comprimido.

function shuffleArray(d) { for (var c = d.length - 1; c > 0; c--) { var b = Math.floor(Math.random() * (c + 1)); var a = d[c]; d[c] = d[b]; d[b] = a; } return d };


Aquí hay una implementación de JavaScript de Durstenfeld shuffle , una versión optimizada por computadora de Fisher-Yates:

/** * Randomize array element order 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; } }

El algoritmo de Fisher-Yates funciona seleccionando un elemento aleatorio para cada elemento de la matriz original, y luego excluyéndolo del siguiente sorteo. Al igual que al azar de una baraja de cartas.

Esta exclusión se realiza de una manera inteligente (inventada por Durstenfeld para uso de computadoras) al intercambiar el elemento elegido con el elemento actual y luego seleccionar el siguiente elemento aleatorio del resto. Para una eficiencia óptima, el bucle se ejecuta hacia atrás para simplificar la selección aleatoria (siempre puede comenzar en 0), y omite el último elemento porque ya no hay otras opciones.

El tiempo de ejecución de este algoritmo es O (n). Tenga en cuenta que la baraja se realiza en el lugar. Entonces, si no desea modificar la matriz original, primero haga una copia con .slice(0) .

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.

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]]; } }


Con ES2015 puedes usar este:

Array.prototype.shuffle = function() { let m = this.length, i; while (m) { i = (Math.random() * m--) >>> 0; [this[m], this[i]] = [this[i], this[m]] } return this; }

Uso:

[1, 2, 3, 4, 5, 6, 7].shuffle();


El algoritmo aleatorio imparcial de facto es el Shuffle de 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 )

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]; arr = shuffle(arr); console.log(arr);

Un poco más de información sobre el algoritmo utilizado.


En primer lugar, eche un vistazo bost.ocks.org/mike/shuffle/compare.html para una gran comparación visual de diferentes métodos de clasificación en javascript.

En segundo lugar, si echa un vistazo rápido al enlace de arriba, encontrará que el random order parece funcionar relativamente bien en comparación con los otros métodos, mientras que es extremadamente fácil y rápido de implementar, como se muestra a continuación:

function shuffle(array) { var random = array.map(Math.random); array.sort(function(a, b) { return random[array.indexOf(a)] - random[array.indexOf(b)]; }); }

Edición : según lo señalado por @gregers, la función de comparación se llama con valores en lugar de índices, por lo que necesita usar indexOf . Tenga en cuenta que este cambio hace que el código sea menos adecuado para matrices más grandes, ya que indexOf ejecuta en tiempo O (n).


Encontré esta variante 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, esto es:

  1. En realidad al azar
  2. No en el lugar (de ahí el nombre shuffled lugar de shuffle )
  3. Ya no está presente aquí con múltiples variantes.

Aquí hay un jsfiddle que lo muestra en uso .

Array.prototype.shuffled = function() { return this.map(function(n){ return [Math.random(), n] }) .sort().map(function(n){ return n[1] }); }


Otra implementación más de Fisher-Yates, utilizando el modo estricto:

function shuffleArray(a) { "use strict"; var i, t, j; for (i = a.length - 1; i > 0; i -= 1) { t = a[i]; j = Math.floor(Math.random() * (i + 1)); a[i] = a[j]; a[j] = t; } return a; }


Puedes hacerlo fácilmente con el mapa y ordenar:

let unshuffled = [''hello'', ''a'', ''t'', ''q'', 1, 2, 3, {cats: true}] let shuffled = unshuffled .map((a) => ({sort: Math.random(), value: a})) .sort((a, b) => a.sort - b.sort) .map((a) => a.value)

  1. Colocamos cada elemento de la matriz en un objeto y le asignamos una clave de orden aleatoria.
  2. Ordenamos usando la clave aleatoria.
  3. Desacoplamos para obtener los objetos originales.

Puede mezclar 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 están ordenados contra claves consistentes que no se regeneran en cada iteración, y cada comparación se extrae de la misma distribución, cualquier no aleatoriedad en la distribución de Math.random se cancela.


Puedes hacerlo fácilmente con:

// array var fruits = ["Banana", "Orange", "Apple", "Mango"]; // random fruits.sort(function(a, b){return 0.5 - Math.random()}); // out console.log(fruits);

Por favor refiérase a JavaScript Ordenar matrices


Todas las demás respuestas se basan en Math.random () que es rápido pero no es adecuado para la aleatorización a nivel criptográfico.

El siguiente código utiliza el conocido algoritmo de Fisher-Yates y utiliza la Web Cryptography API de criptografía Web Cryptography API para el nivel criptográfico de aleatorización .

var d = [1,2,3,4,5,6,7,8,9,10]; function shuffle(a) { var x, t, r = new Uint32Array(1); for (var i = 0, c = a.length - 1, m = a.length; i < c; i++, m--) { crypto.getRandomValues(r); x = Math.floor(r / 65536 / 65536 * m) + i; t = a [i], a [i] = a [x], a [x] = t; } return a; } console.log(shuffle(d));


Una forma muy simple para arreglos pequeños es simplemente esta:

const someArray = [1, 2, 3, 4, 5]; someArray.sort(() => Math.random() - 0.5);

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.

const resultsEl = document.querySelector(''#results''); const buttonEl = document.querySelector(''#trigger''); const generateArrayAndRandomize = () => { const someArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; someArray.sort(() => Math.random() - 0.5); return someArray; }; const renderResultsToDom = (results, el) => { el.innerHTML = results.join('' ''); }; buttonEl.addEventListener(''click'', () => renderResultsToDom(generateArrayAndRandomize(), resultsEl));

<h1>Randomize!</h1> <button id="trigger">Generate</button> <p id="results">0 1 2 3 4 5 6 7 8 9</p>


Una solución recursiva:

function shuffle(a,b){ return a.length==0?b:function(c){ return shuffle(a,(b||[]).concat(c)); }(a.splice(Math.floor(Math.random()*a.length),1)); };


Uno podría (o debería) usarlo como un prototipo de Array:

De ChristopheD:

Array.prototype.shuffle = function() { var i = this.length, j, temp; if ( i == 0 ) return this; while ( --i ) { j = Math.floor( Math.random() * ( i + 1 ) ); temp = this[i]; this[i] = this[j]; this[j] = temp; } return this; }


Utilice la biblioteca underscore.js. El método _.shuffle() es bueno para este caso. Aquí hay un ejemplo con el método:

var _ = require("underscore"); var arr = [1,2,3,4,5,6]; // Testing _.shuffle var testShuffle = function () { var indexOne = 0; var stObj = { ''0'': 0, ''1'': 1, ''2'': 2, ''3'': 3, ''4'': 4, ''5'': 5 }; for (var i = 0; i < 1000; i++) { arr = _.shuffle(arr); indexOne = _.indexOf(arr, 1); stObj[indexOne] ++; } console.log(stObj); }; testShuffle();


[edit de la comunidad: esta respuesta es incorrecta; ver comentarios. Se está dejando aquí para futuras referencias porque la idea no es tan rara.]

[1,2,3,4,5,6].sort(function() { return .5 - Math.random(); });


Fisher-Yates shuffle 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í.

function swap(arr, i, j) { // swaps two elements of an array in place var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } function randInt(max) { // returns random integer between 0 and max-1 inclusive. return Math.floor(Math.random()*max); } function shuffle(arr) { // For each slot in the array (starting at the end), // pick an element randomly from the unplaced elements and // place it in the slot, exchanging places with the // element in the slot. for(var slot = arr.length - 1; slot > 0; slot--){ var element = randInt(slot+1); swap(arr, element, slot); } }


Matriz aleatoria

var arr = [''apple'',''cat'',''Adam'',''123'',''Zorro'',''petunia'']; var n = arr.length; var tempArr = []; for ( var i = 0; i < n-1; i++ ) { // The following line removes one random element from arr // and pushes it onto tempArr tempArr.push(arr.splice(Math.floor(Math.random()*arr.length),1)[0]); } // Push the remaining item onto tempArr tempArr.push(arr[0]); arr=tempArr;


Solución moderna en línea corta que utiliza las características de ES6:

[''a'',''b'',''c'',''d''].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);

(para fines educativos)


Aleatorizar array usando array.splice ()

function shuffleArray(array) { var temp = []; var len=array.length; while(len){ temp.push(array.splice(Math.floor(Math.random()*array.length),1)[0]); len--; } return temp; } //console.log("Here >>> "+shuffleArray([4,2,3,5,8,1,0]));

demo


Aunque ya hay varias implementaciones recomendadas, pero creo que podemos hacerlas más cortas y fáciles usando forEach loop, por lo que no debemos preocuparnos por calcular la longitud de la matriz y también podemos evitar el uso seguro de una variable temporal.

var arr1 = ["a", "b", "c", "d"]; arr1.forEach((val, key) => { randomIndex = Math.ceil(Math.random()*(key + 1)); arr1[key] = arr1[randomIndex]; arr1[randomIndex] = val; });


Curiosamente, no hubo una respuesta recursiva no mutante:

var shuffle = arr => { const recur = (arr,currentIndex)=>{ console.log("fuck?",JSON.stringify(arr)) if(currentIndex===0){ return arr; } const randomIndex = Math.floor(Math.random() * currentIndex); const swap = arr[currentIndex]; arr[currentIndex] = arr[randomIndex]; arr[randomIndex] = swap; return recur( arr, currentIndex - 1 ); } return recur(arr.map(x=>x),arr.length-1); }; var arr = [1,2,3,4,5,[6]]; console.log(shuffle(arr)); console.log(arr);


Desde un punto de vista teórico, la forma más elegante de hacerlo, en mi humilde opinión, es obtener un solo número aleatorio entre 0 y n! -1 y calcular una asignación uno a uno de {0, 1, …, n!-1}todas las permutaciones de (0, 1, 2, …, n-1). Mientras pueda usar un generador (pseudo) aleatorio lo suficientemente confiable para obtener tal número sin ningún sesgo significativo, tiene suficiente información para lograr lo que desea sin necesidad de otros números aleatorios.

Al calcular con números flotantes de doble precisión IEEE754, puede esperar que su generador aleatorio proporcione aproximadamente 15 decimales. Ya que tiene 15! = 1,307,674,368,000 (con 13 dígitos), puede usar las siguientes funciones con arreglos que contienen hasta 15 elementos y suponga que no habrá sesgo significativo con arreglos que contengan hasta 14 elementos. Si trabaja en un problema de tamaño fijo que requiere calcular varias veces esta operación aleatoria, es posible que desee probar el siguiente código, que puede ser más rápido que otros códigos ya que se usa Math.randomsolo una vez (sin embargo, implica varias operaciones de copia).

La siguiente función no será utilizada, pero la doy de todos modos; devuelve el índice de una permutación determinada de (0, 1, 2, …, n-1)acuerdo con la asignación uno a uno utilizada en este mensaje (la más natural al enumerar las permuaciones); Se pretende trabajar con hasta 16 elementos:

function permIndex(p) { var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000]; var tail = []; var i; if (p.length == 0) return 0; for(i=1;i<(p.length);i++) { if (p[i] > p[0]) tail.push(p[i]-1); else tail.push(p[i]); } return p[0] * fact[p.length-1] + permIndex(tail); }

El recíproco de la función anterior (requerido para su propia pregunta) se encuentra a continuación; está pensado para trabajar con hasta 16 elementos; devuelve la permutación de orden n de (0, 1, 2, …, s-1):

function permNth(n, s) { var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000]; var i, j; var p = []; var q = []; for(i=0;i<s;i++) p.push(i); for(i=s-1; i>=0; i--) { j = Math.floor(n / fact[i]); n -= j*fact[i]; q.push(p[j]); for(;j<i;j++) p[j]=p[j+1]; } return q; }

Ahora, lo que quieres es simplemente:

function shuffle(p) { var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000]; return permNth(Math.floor(Math.random()*fact[p.length]), p.length).map( function(i) { return p[i]; }); }

Debería funcionar para hasta 16 elementos con un poco de sesgo teórico (aunque no se nota desde un punto de vista práctico); Puede verse como completamente utilizable para 15 elementos; con matrices que contienen menos de 14 elementos, puede considerar con seguridad que no habrá absolutamente ningún sesgo.


Sólo para tener un dedo en el pastel. Aquí presento una implementación recursiva de Fisher Yates shuffle (creo). Da uniformidad al azar.

Nota: El ~~(operador de doble tilde) de hecho se comporta como Math.floor()para números reales positivos. Sólo un atajo es.

var shuffle = a => a.length ? a.splice(~~(Math.random()*a.length),1).concat(shuffle(a)) : a; console.log(JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9])));


Una simple modificación de la answer de CoolAJ86 que no modifica la matriz original:

/** * Returns a new array whose contents are a shuffled copy of the original array. * @param {Array} The items to shuffle. * https://.com/a/2450976/1673761 * https://.com/a/44071316/1673761 */ const shuffle = (array) => { let currentIndex = array.length; let temporaryValue; let randomIndex; const newArray = array.slice(); // While there remains elements to shuffle... while (currentIndex) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // Swap it with the current element. temporaryValue = newArray[currentIndex]; newArray[currentIndex] = newArray[randomIndex]; newArray[randomIndex] = temporaryValue; } return newArray; };


la arrayShufflefunción más corta

function arrayShuffle(o) { for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); return o; }


Array.prototype.shuffle=function(){ var len = this.length,temp,i while(len){ i=Math.random()*len-- |0; temp=this[len],this[len]=this[i],this[i]=temp; } return this; }


var shuffle = function(array) { temp = []; for (var i = 0; i < array.length ; i++) { temp.push(array.splice(Math.floor(Math.random()*array.length),1)); } return temp; };