elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


Tema destacado: Arreglado, de nuevo, el registro del warzone (wargame) de EHN


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  ¿Qué método es recomendado para ordenar al azar un array?
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: ¿Qué método es recomendado para ordenar al azar un array?  (Leído 1,030 veces)
Tachikomaia


Desconectado Desconectado

Mensajes: 1.503


Hackentifiko!


Ver Perfil
¿Qué método es recomendado para ordenar al azar un array?
« en: 7 Enero 2025, 07:16 am »

Probablemente los lenguajes modernos tienen una función que lo hace, no busco eso.

Yo había pensado algo así:
Código
  1. Colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"];
  2. // Esto habría que hacerlo con loop pero no es lo relevante:
  3. PesoDeElementos = [Math.random(), Math.random(), Math.random(), Math.random(), Math.random()];
  4. Elemento1aReubicarse = -1;
  5. ReordenarHasta = 4;
  6. do {
  7. Elemento1aReubicarse++;
  8. Elemento2aReubicarse = Elemento1aReubicarse+1;
  9. if (PesoDeElementos[Elemento1aReubicarse] > PesoDeElementos[Elemento2aReubicarse]) {
  10. // Intercambiar esos 2 elementos:
  11. SaveDeElemento1 = Colores[Elemento1aReubicarse];
  12. Colores[Elemento1aReubicarse] = Colores[Elemento2aReubicarse];
  13. Colores[Elemento1aReubicarse] = SaveDeElemento1;
  14. }
  15. if (Elemento2aReubicarse == ReordenarHasta) {
  16. // Hacia la derecha ya está reordenado, volver a la izquierda:
  17. Elemento1aReubicarse = -1;
  18. ReordenarHasta--;
  19. }
  20. } while (ReordenarHasta > 0);

Pero suponiendo que podía haber algo más sencillo (esa cosa la acabo de hacer, no sé si funciona), le pregunté a GPT. Me dijo un método de Fisher o algo así que no entendí. En Wikipedia tampoco. Pero se me ocurrió (o puede ser igual a lo que no entendí) un método que recorra los elementos, hasta el central, intercambiando los de un lado con los de otro, y luego el central con cualquiera, pero tenía dudas de cómo sería exactamente y ahora noto que no sería justo, es decir, el 1er elemento nunca quedaría 2ndo (salvo que fuesen menos de 4), y además:
- Si siempre hay intercambio, nunca podrían quedar en el lugar original, lo cual debería poder suceder.
- Si puede no haber intercambio, la probabilidad de que queden igual varios de ellos es muy alta.
Así que eso no sirve ¿pero cual es entonces un buen método?

Copio la conversación que tuve con GPT:
Citar
En **Macromedia Flash 5**, que utiliza **ActionScript 1.0**, puedes implementar un algoritmo para reordenar un array al azar utilizando un enfoque conocido como el algoritmo de **Fisher-Yates Shuffle**. Aquí tienes el código que puedes usar para reordenar al azar el array `PosiblesColores`:

```actionscript
// Array original
PosiblesColores = [0xFFFFFF, 0xFF0000, 0]; // Puedes agregar hasta 10 elementos

// Función para reordenar el array al azar
function shuffleArray(array) {
    var i, j, temp;
    for (i = array.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1)); // Genera un índice aleatorio válido
        // Intercambia los elementos array y array[j]
        temp = array;
        array = array[j];
        array[j] = temp;
    }
}

// Llama a la función para mezclar el array
shuffleArray(PosiblesColores);

// Imprime el array reordenado para verificar
for (var i = 0; i < PosiblesColores.length; i++) {
    trace(PosiblesColores);
}
```

### Explicación del código:
1. **Algoritmo Fisher-Yates**:
   - Este algoritmo recorre el array desde el último elemento hasta el primero.
   - En cada iteración, selecciona un índice aleatorio entre `0` y el índice actual, e intercambia los dos elementos.
   - Esto garantiza que cada permutación del array sea igualmente probable.

2. **`Math.random()`**:
   - Genera un número decimal aleatorio entre `0` y `1`.
   - Multiplicamos este número por el rango necesario (`i + 1`) para obtener un índice aleatorio válido.

3. **Intercambio de elementos**:
   - Usamos una variable temporal (`temp`) para almacenar el valor de uno de los elementos mientras realizamos el intercambio.

4. **`trace()`**:
   - Esta función imprime los valores en el panel de salida para que puedas verificar el resultado del reordenamiento.

### Ejemplo de salida:
Si el array original es:

```actionscript
PosiblesColores = [0xFFFFFF, 0xFF0000, 0];
```

Después de ejecutar el código, el array podría quedar como:

```actionscript
[0, 0xFFFFFF, 0xFF0000]
```

O cualquier otra permutación aleatoria de los elementos.

Puedes modificar el array `PosiblesColores` para agregar más elementos, y el algoritmo seguirá funcionando correctamente.

quisiera que el índice vaya subiendo en vez de bajando y que uses while en vez de for

Citar
¡Claro! Aquí está el código modificado para que el índice vaya **subiendo** y se use un bucle `while` en lugar de `for`. El algoritmo sigue siendo equivalente al **Fisher-Yates Shuffle**, pero adaptado a tus especificaciones:

```actionscript
// Array original
PosiblesColores = [0xFFFFFF, 0xFF0000, 0]; // Puedes agregar hasta 10 elementos

// Función para reordenar el array al azar
function shuffleArray(array) {
    var i = 0;  // Empieza desde el primer índice
    var len = array.length;

    while (i < len - 1) {
        // Genera un índice aleatorio entre i y el último índice
        var j = Math.floor(Math.random() * (len - i)) + i;

        // Intercambia los elementos array y array[j]
        var temp = array;
        array = array[j];
        array[j] = temp;

        // Incrementa el índice
        i++;
    }
}

// Llama a la función para mezclar el array
shuffleArray(PosiblesColores);

// Imprime el array reordenado para verificar
var index = 0;
while (index < PosiblesColores.length) {
    trace(PosiblesColores[index]);
    index++;
}
```

### Cambios realizados:
1. **Uso de `while`**:
   - El índice `i` comienza en `0` y se incrementa en cada iteración hasta el penúltimo elemento (`len - 1`).
   - El bucle `while` se detiene cuando el índice `i` alcanza el penúltimo elemento.

2. **Generación de índice aleatorio (`j`)**:
   - En lugar de seleccionar un índice aleatorio para cualquier posición del array, `j` se selecciona entre `i` (el índice actual) y el final del array.
   - Esto asegura que cada elemento solo sea intercambiado con los elementos que aún no han sido procesados.

3. **Intercambio de elementos**:
   - Igual que antes, usamos una variable temporal `temp` para realizar el intercambio entre `array` y `array[j]`.

4. **Impresión con `while`**:
   - Se utiliza un bucle `while` para imprimir cada elemento del array después de ser mezclado.

### Ejemplo de salida:
Dado el array original:

```actionscript
PosiblesColores = [0xFFFFFF, 0xFF0000, 0];
```

Después de ejecutar el código, podrías obtener una permutación como:

```actionscript
[0xFF0000, 0, 0xFFFFFF]
```

O cualquier otra ordenación aleatoria.

Este código es completamente funcional y cumple con las especificaciones que pediste.

Intenté imitarlo pero como no sé exacto cómo funciona y esos nombres j e i me entreveran, decidí buscar en Wikipedia.
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

Creo que ahora entiendo, va desde derecha a izquierda y "rolled" significa que eligió intercambiar con ese, el elemento posible de intercambiarse era el 4 y "rolled" un 1, yo interpretaba que había elegido por azar el 1 y no sabía de dónde había sacado el 4.

¿Es así? ¿hay otro mejor?


En línea

blckkey

Desconectado Desconectado

Mensajes: 67


Priest


Ver Perfil
Re: ¿Qué método es recomendado para ordenar al azar un array?
« Respuesta #1 en: 7 Enero 2025, 12:30 pm »

Vale, te explico. Lo que estás viendo con el algoritmo Fisher-Yates no es tan complicado como parece. Básicamente, lo que hace es recorrer el array desde el final hacia el principio, eligiendo un índice aleatorio en cada paso e intercambiándolo. Es eficiente porque garantiza un desordenado (shuffle) uniforme sin repeticiones raras.

Lo que pedías, cambiar el índice para que suba en lugar de bajar y usar un while en vez de un for, también funciona, pero en realidad es darle una vuelta innecesaria a algo que ya está optimizado. Fisher-Yates está diseñado para ir de atrás hacia adelante porque así evita tocar posiciones ya desordenadas.

La versión que adaptaste usando while y contando hacia arriba también hace el trabajo. Solo que, al hacerlo así, terminas haciendo intercambios adicionales para llegar al final, mientras que la versión original reduce el rango en cada paso. No es que esté mal, pero puede ser un poco menos eficiente si trabajas con arrays muy grandes.

La parte que mencionas de "rolled" puede ser confusa si lo interpretas como que el número seleccionado ya estaba fijo. En realidad, es solo un índice aleatorio dentro del rango restante, así que cada paso elige un candidato para intercambiar con el actual. No te quedas limitado a los valores anteriores, siempre es algo dinámico.

Si lo que quieres es seguir con tu idea, prueba imprimir el array en cada paso del bucle para ver exactamente qué está pasando en cada intercambio. Eso ayuda mucho para visualizar cómo se va desordenando. Pero vamos, que la versión original es más directa y hace exactamente lo mismo.


En línea

"What you call security, I call an invitation..."
EdePC
Moderador Global
***
Desconectado Desconectado

Mensajes: 2.198



Ver Perfil
Re: ¿Qué método es recomendado para ordenar al azar un array?
« Respuesta #2 en: 7 Enero 2025, 15:02 pm »

El FOR ya deberías de dominarlo porque te lo expliqué varias veces y convertirlo a WHILE es inmediato, son completamente equivalentes para estas cosas sencillas donde hay inicialización de variable, condición y actualización de variable.

Quizá renombrando variables y adaptándolo más las instrucciones de ActionScript que sueles utilizar se te haga más legible:

Código
  1. colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"]
  2.  
  3. posicion1aReubicarse = colores.length - 1
  4. while (posicion1aReubicarse > 0) {
  5.  posicion2aReubicarse = random(posicion1aReubicarse)
  6.  saveDeElemento1 = colores[posicion1aReubicarse]
  7.  colores[posicion1aReubicarse] = colores[posicion2aReubicarse]
  8.  colores[posicion2aReubicarse ] = SaveDeElemento1
  9.  posicion1aReubicarse--
  10. }
  11.  
  12. trace(Colores)

Resumen: Se toma el último elemento (el de la derecha), luego aleatoriamente se elige otro elemento (alguno situado a la izquierda del elemento elegido anteriormente), entonces se intercambian ambos elementos. Se continúa haciendo lo mismo con el penúltimo elemento, luego con el antepenúltimo y así sucesivamente.

1. Crea el Array de elementos a desordenar
3. Se inicializa posicion1aReubicarse al número de elementos del Array -1, para obtener el último índice válido para el Array, este indicará el primer elemento a reubicar
4. El WHILE, la condición para continuar es que posicion1aReubicarse sea mayor que 0 porque si fuera 0 ya no habría con quien hacer el intercambio
5. Generamos un número aleatorio entre 0 y el índice actual (no incluye a este último) para determinar el índice del segundo elemento a reubicar, para la primera iteración puede ser: 0, 1, 2, o 3
6. Guardamos el primer elemento a reubicar para no perderlo
7 y 8. Hacemos el intercambio, ponemos el segundo elemento a reubicar en lugar del primero, luego ponemos el primer elemento a reubicar (que se ha guardado porque lo perdimos en la línea 7) en lugar del segundo
9. Decrementamos posicion1aReubicarse para ir a por el penúltimo elemento, luego por el antepenúltimo y así sucesivamente

La razón de avanzar de atrás hacia adelante (del último al primero) es para simplificar la generación del número aleatorio y que sea más legible, pero el funcionamiento es completamente igual. Si avanzaras desde el primero al último tendría que ser:

Código
  1. colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"]
  2.  
  3. posicion1aReubicarse = 0
  4. while (posicion1aReubicarse < colores.length - 1) {
  5.  posicion2aReubicarse = random( colores.length - (posicion1aReubicarse + 1) ) + posicion1aReubicarse + 1
  6.  saveDeElemento1 = colores[posicion1aReubicarse]
  7.  colores[posicion1aReubicarse] = colores[posicion2aReubicarse]
  8.  colores[posicion2aReubicarse ] = SaveDeElemento1
  9.  posicion1aReubicarse++
  10. }
  11.  
  12. trace(Colores)
En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 1.503


Hackentifiko!


Ver Perfil
Re: ¿Qué método es recomendado para ordenar al azar un array?
« Respuesta #3 en: 8 Enero 2025, 06:45 am »

Ok a los dos.

Ojo, EdePC, que según mi interpretación de tu código ningún elemento puede quedar donde estaba, o sólo el 1ero. Voy a probarlo y te aviso si me equivoqué.

Me cuesta entender el por qué de tantas cuentas cuando se va de izquierda a derecha, lo voy a pensar.

Edit: Hice varias pruebas y sucedió eso:
Rojo,Negro,Azul,Verde,Blanco
Blanco,Negro,Rojo,Verde,Azul
Verde,Blanco,Rojo,Negro,Azul
Verde,Negro,Rojo,Azul,Blanco
Blanco,Azul,Negro,Verde,Rojo
Rojo,Blanco,Negro,Verde,Azul
Verde,Azul,Negro,Rojo,Blanco
Rojo,Verde,Negro,Azul,Blanco
Verde,Negro,Rojo,Azul,Blanco
Rojo,Blanco,Negro,Verde,Azul
Rojo,Verde,Blanco,Negro,Azul
Negro,Blanco,Rojo,Azul,Verde
Verde,Azul,Blanco,Negro,Rojo
Blanco,Verde,Azul,Negro,Rojo
Rojo,Verde,Negro,Azul,Blanco
Verde,Blanco,Negro,Azul,Rojo
Blanco,Azul,Negro,Verde,Rojo
Verde,Azul,Negro,Rojo,Blanco
Verde,Azul,Negro,Rojo,Blanco
Blanco,Verde,Azul,Negro,Rojo
Negro,Verde,Azul,Rojo,Blanco
Verde,Negro,Rojo,Azul,Blanco
Verde,Negro,Blanco,Rojo,Azul
Blanco,Negro,Azul,Rojo,Verde
Rojo,Negro,Azul,Verde,Blanco
Verde,Blanco,Negro,Azul,Rojo
Blanco,Verde,Negro,Rojo,Azul
Verde,Blanco,Negro,Azul,Rojo
Rojo,Blanco,Negro,Verde,Azul
Negro,Verde,Blanco,Azul,Rojo
Rojo,Blanco,Azul,Negro,Verde
Negro,Verde,Blanco,Azul,Rojo
Negro,Blanco,Rojo,Azul,Verde

El negro nunca quedó último, el blanco nunca penúltimo, el verde nunca 3ero, el rojo nunca 2ndo, y hasta el azul nunca 1ero. No sé si fue tu intención hacerlo así porque no nos entendimos o es un error. Cuando dije reordenar, me refería a también a la posibilidad de que no haya cambios. Pensaré la solución.

Edit:
Solución con contador incluído:
Código
  1. Posicion = -1;
  2. do {
  3. Posicion++;
  4. set ("AzulEn"+Posicion, 0);
  5. set ("RojoEn"+Posicion, 0);
  6. set ("VerdeEn"+Posicion, 0);
  7. set ("BlancoEn"+Posicion, 0);
  8. set ("NegroEn"+Posicion, 0);
  9. } while (Posicion<4);
  10. Repeticion = 0;
  11. do {
  12. Repeticion++;
  13. colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"];
  14. posicion1aReubicarse = colores.length-1;
  15. while (posicion1aReubicarse>0) {
  16. posicion2aReubicarse = random(posicion1aReubicarse+1);
  17. // trace (Colores[posicion1aReubicarse]+" se intercambiará con "+Colores[posicion2aReubicarse]);
  18. saveDeElemento1 = colores[posicion1aReubicarse];
  19. colores[posicion1aReubicarse] = colores[posicion2aReubicarse];
  20. colores[posicion2aReubicarse] = SaveDeElemento1;
  21. Resumen = colores[posicion1aReubicarse]+"En"+posicion1aReubicarse;
  22. set (Resumen, eval(Resumen)+1);
  23. //trace(Resumen);
  24. posicion1aReubicarse--;
  25. }
  26. Resumen = colores[posicion1aReubicarse]+"En"+posicion1aReubicarse;
  27. set (Resumen, eval(Resumen)+1);
  28. //trace(Resumen);
  29. trace (Colores);
  30. } while (Repeticion<1000);
  31. Posicion = -1;
  32. do {
  33. Posicion++;
  34. trace ("AzulEn"+Posicion+": "+eval("AzulEn"+Posicion));
  35. trace ("RojoEn"+Posicion+": "+eval("RojoEn"+Posicion));
  36. trace ("VerdeEn"+Posicion+": "+eval("VerdeEn"+Posicion));
  37. trace ("BlancoEn"+Posicion+": "+eval("BlancoEn"+Posicion));
  38. trace ("NegroEn"+Posicion+": "+eval("NegroEn"+Posicion));
  39. } while (Posicion<4);
AzulEn0: 207
RojoEn0: 205
VerdeEn0: 195
BlancoEn0: 189
NegroEn0: 204
AzulEn1: 198
RojoEn1: 195
VerdeEn1: 224
BlancoEn1: 185
NegroEn1: 198
AzulEn2: 208
RojoEn2: 198
VerdeEn2: 203
BlancoEn2: 180
NegroEn2: 211
AzulEn3: 187
RojoEn3: 194
VerdeEn3: 204
BlancoEn3: 219
NegroEn3: 196
AzulEn4: 200
RojoEn4: 208
VerdeEn4: 174
BlancoEn4: 227
NegroEn4: 191

O sea, más o menos todos quedaron en todas las posiciones la misma cantidad de veces. Tengo mis dudas sobre si es parejo en cuanto a la probabilidad de que cambien de posición pero tampoco es tan importante, ya está bastante bien.
« Última modificación: 8 Enero 2025, 07:33 am por Tachikomaia » En línea

EdePC
Moderador Global
***
Desconectado Desconectado

Mensajes: 2.198



Ver Perfil
Re: ¿Qué método es recomendado para ordenar al azar un array?
« Respuesta #4 en: 8 Enero 2025, 13:04 pm »

Ok a los dos.

Ojo, EdePC, que según mi interpretación de tu código ningún elemento puede quedar donde estaba

Si, es intencional, y es porque el número aleatorio se forma para seleccionar el segundo elemento sin incluir al primero:

colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"]

Si tomas como primer elemento "Negro" el segundo elemento está restringido a ser cualquiera de los de la izquierda. Si llevamos ese algoritmo al mundo real: tienes 5 bolitas de colores en un cesto, tomas la bolita negra y luego debes tomar otra, ahí la decisión de volver a poner la bolita negra en el cesto para que haya la posibilidad de volverla a elegir es completamente tuya

Es decir, te basta con sumarle +1 al límite de la generación del número aleatorio para que incluya a la posición del elemento seleccionado previamente:

Código
  1. colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"]
  2.  
  3. posicion1aReubicarse = colores.length -1
  4. while (posicion1aReubicarse > 0) {
  5.  posicion2aReubicarse = random(posicion1aReubicarse +1)
  6.  saveDeElemento1 = colores[posicion1aReubicarse]
  7.  colores[posicion1aReubicarse] = colores[posicion2aReubicarse]
  8.  colores[posicion2aReubicarse] = SaveDeElemento1
  9.  posicion1aReubicarse--
  10. }
  11.  
  12. trace(colores)

Citar
O sea, más o menos todos quedaron en todas las posiciones la misma cantidad de veces. Tengo mis dudas sobre si es parejo en cuanto a la probabilidad de que cambien de posición pero tampoco es tan importante, ya está bastante bien.

Siempre o casi siempre los lenguajes de programación mencionan lo siguiente para las funciones Random: Genera un número pseudoaleatorio, y peor con la función Random de ActionScript, menciona que es una emulación de la función Math.Random usando aproximaciones y que se prefiere esta última. Da a suponer que lo mejor sería utilizar Math.Random aunque habrá que ver que tanto cambia al final, quizá con muestras mucho más grandes se noten variaciones importantes:

Código
  1. colores = ["Azul", "Rojo", "Verde", "Blanco", "Negro"]
  2.  
  3. posicion1aReubicarse = colores.length - 1
  4. while (posicion1aReubicarse > 0) {
  5.  posicion2aReubicarse = Math.floor( Math.random() * (posicion1aReubicarse +1) )
  6.  saveDeElemento1 = colores[posicion1aReubicarse]
  7.  colores[posicion1aReubicarse] = colores[posicion2aReubicarse]
  8.  colores[posicion2aReubicarse ] = SaveDeElemento1
  9.  posicion1aReubicarse--
  10. }
  11.  
  12. trace(Colores)

El detalle es que se pierde algo de legibilidad si no estás acostumbrado a usar Math.random y ni que decir si usaras el algoritmo incrementando en lugar de decrementar XD
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Problema ordenando array al azar « 1 2 »
Programación Visual Basic
$Edu$ 12 4,322 Último mensaje 30 Septiembre 2011, 04:44 am
por $Edu$
Ayuda con código para re ordenar array « 1 2 3 »
Programación C/C++
ZedGe 21 9,248 Último mensaje 7 Abril 2013, 16:37 pm
por 85
Ayuda para ordenar Array
.NET (C#, VB.NET, ASP)
bybaal 2 2,910 Último mensaje 15 Abril 2016, 12:37 pm
por bybaal
Necesito agregar a mi archivo un metodo para ordenar - JAVA
Java
JAZzZ 1 3,014 Último mensaje 5 Agosto 2017, 21:40 pm
por ivancea96
¿Cual es el método más simple de obtener 1 o -1 por azar?
Programación General
Tachikomaia 2 4,249 Último mensaje 24 Octubre 2023, 17:33 pm
por Tachikomaia
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines