Foros del Web » Programando para Internet » Javascript »

Optimización: Escoger un elemento aleatorio de un array no escogido ya

Estas en el tema de Optimización: Escoger un elemento aleatorio de un array no escogido ya en el foro de Javascript en Foros del Web. Hola. Propongo un concursillo, quien gane se llevará una cervecilla . Consiste en lo siguiente: Dado un array de n elementos de tipos no necesariamente ...
  #1 (permalink)  
Antiguo 10/11/2007, 08:16
Avatar de derkenuke
Colaborador
 
Fecha de Ingreso: octubre-2003
Ubicación: self.location.href
Mensajes: 2.665
Antigüedad: 20 años, 6 meses
Puntos: 45
Optimización: Escoger un elemento aleatorio de un array no escogido ya

Hola.

Propongo un concursillo, quien gane se llevará una cervecilla . Consiste en lo siguiente:

Dado un array de n elementos de tipos no necesariamente iguales, mediante una función f() devolver un elemento aleatorio de ese array. En sucesivas llamadas a esta función se deberá devolver también elementos aleatorios de este array, sin poderse devolver los mismos elementos. Es decir, una vez devuelto un elemento, ya no lo podremos obtener otra vez. Cuando no queden elementos que no hayan sido devueltos, la función debe devolver un false.

Se trata de resolver el ejercicio lo más eficientemente posible (que yo ya sé resolverlo a lo bestia ). Quien consiga en menos milisegundos devolver todos los elementos (hasta que se devuelva false) se lleva la birra


Dejo un array de base para que podamos trabajar todos sobre lo mismo (he hecho un popurrí de elementos...):
Código PHP:
var miArray = ['flgo'20'pgre'2213816'frkiysoj'9Infinity1114true'bstuhcv''bhatnck'717'nusfgcvd'1921'gmwp''incauo''hqu', { color"rojo"forma"cuadrado" }, 'kficoprn''qofxpdsn''ugdoebq''kxmhs'3'bfce''neduh'15'ueifchsj''kgdmj''ojk''vfqoyhli''buno'18'nrkmf'12623'hnvroupj''gkdtnhq'document.body10'qghsfpdr'241window.screenundefinednull0'ewgmq'NaN4, function () { }, 25window.onloadvoid(0), -Infinity]; 
No sé si será demasiado corto, creo que sí... bueno si nos vemos en dificultades para testear probaremos en ordenadores lentos o aumentaremos el array


¿Quién se apunta?
__________________
- Haz preguntas inteligentes, y obtendrás más y mejores respuestas.
- Antes de postearlo Inténtalo y Búscalo.
- Escribe correctamente tus mensajes.
  #2 (permalink)  
Antiguo 11/11/2007, 11:43
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Re: Optimización: Escoger un elemento aleatorio de un array no escogido ya

A ver pues, un primer intento que seguramente sea la forma en que lo resolverías "a lo bestia"

Código PHP:
var miArray = ['flgo'20'pgre'2213816'frkiysoj'9Infinity1114true'bstuhcv''bhatnck'717'nusfgcvd'1921'gmwp''incauo''hqu', { color"rojo"forma"cuadrado" }, 'kficoprn''qofxpdsn''ugdoebq''kxmhs'3'bfce''neduh'15'ueifchsj''kgdmj''ojk''vfqoyhli''buno'18'nrkmf'12623'hnvroupj''gkdtnhq'document.body10'qghsfpdr'241window.screenundefinednull0'ewgmq'NaN4, function () { }, 25window.onloadvoid(0), -Infinity];
var 
yaElegidos = [];
var 
largo miArray.length;

function 
dameElemento() {
    
largoElegidos yaElegidos.length;
    if ( 
largoElegidos largo ) {
        
// termina con 'indice' siendo un índice de la matriz que todavía no fue elegido.
        
while ( yaElegidos.indexOf(indice Math.floorMath.random() * largo )) !== -);
        
yaElegidos[largoElegidos] = indice;
        return 
miArray[indice];
    }
    else
        return 
false;

Opera me da un error en el while, 'type mismatch'. No logro identificar el por qué

Saludos.

Última edición por AlvaroG; 11/11/2007 a las 12:01
  #3 (permalink)  
Antiguo 11/11/2007, 20:45
Avatar de derkenuke
Colaborador
 
Fecha de Ingreso: octubre-2003
Ubicación: self.location.href
Mensajes: 2.665
Antigüedad: 20 años, 6 meses
Puntos: 45
Re: Optimización: Escoger un elemento aleatorio de un array no escogido ya

Hola alvlin, gracias por responder.

En IE también me da fallo, creo que es por no definir el indexOf para arrays. En FF no me ha dado ningún error O_o, no sabía que estuviera implementado...

Bueno, lo he definido así con tu permiso:
Código PHP:
Array.prototype.indexOf = function(x) {
    for(var 
i=0l=this.lengthi<li++)
        if( 
=== this[i] ) return true;
    return -
1;

Dime si lo definirías más eficientemente.

Mi forma bruta sería algo parecida. Tendría un número de escogidos (tu equivalente a yaElegidos.length) y un array de la misma longitud que miArray, que sólo almacenaría 1 en la posición i en caso de haber escogido ya la posición i en el original miArray.

Por otra parte he hecho miArray unas cuantas veces más largo... He utilizado este ejemplo (con medida de tiempo incluída):
Código PHP:
var miArray = ['flgo'20'pgre'2213816'frkiysoj'9Infinity1114true'bstuhcv''bhatnck'717'nusfgcvd'1921'gmwp''incauo''hqu', { color"rojo"forma"cuadrado" }, 'kficoprn''qofxpdsn''ugdoebq''kxmhs'3'bfce''neduh'15'ueifchsj''kgdmj''ojk''vfqoyhli''buno'18'nrkmf'12623'hnvroupj''gkdtnhq'document.body10'qghsfpdr'241window.screenundefinednull0'ewgmq'NaN4, function () { }, 25window.onloadvoid(0), -Infinity];
for(var 
i=0i<5i++)
    
miArray miArray.concat(miArray);
var 
largo miArray.length;
Array.
prototype.yaEscogido = new Array();
Array.
prototype.escogidos 0;

Array.
prototype.elemNoEscogido = function() {
    if( 
this.escogidos largo ) {
        var 
iAleat;
        do {
            
iAleat Math.floorMath.random()*largo );
        } while( 
this.yaEscogido[iAleat] === );
        
this.yaEscogido[iAleat] = 1;
        
this.escogidos++;
        return 
this[iAleat];
    }
    else {
        
//reiniciando
        
this.yaEscogido = new Array();
        
this.escogidos 0;
        return 
false;
    }

// hago la medicion de tiempo 10 veces para hacer una media:
var tiempos = [];
for(var 
t=0t<10t++) {
    var 
ini = new Date().getTime();
    do {
        var 
elem miArray.elemNoEscogido();
    } while(
elem!==false);
    var 
fin = (new Date().getTime()-ini);
    
tiempos.push(fin);
}
// hago la media de tiempos:
var tardanza = eval( "("+tiempos.join("+")+") / "tiempos.length )
document.write("Tiempos: "+tiempos+" --> Tiempo medio: "+tardanza); 
Bajo win y FF me da unos tiempos, por ejemplo, de
Tiempos: 170,281,120,250,251,140,260,130,251,290 --> Tiempo medio: 214.3

He intentado hacer una prueba similar con tu código:
Código PHP:
var miArray = ['flgo'20'pgre'2213816'frkiysoj'9Infinity1114true'bstuhcv''bhatnck'717'nusfgcvd'1921'gmwp''incauo''hqu', { color"rojo"forma"cuadrado" }, 'kficoprn''qofxpdsn''ugdoebq''kxmhs'3'bfce''neduh'15'ueifchsj''kgdmj''ojk''vfqoyhli''buno'18'nrkmf'12623'hnvroupj''gkdtnhq'document.body10'qghsfpdr'241window.screenundefinednull0'ewgmq'NaN4, function () { }, 25window.onloadvoid(0), -Infinity];
for(var 
i=0i<4i++)
    
miArray miArray.concat(miArray);
var 
yaElegidos = []; 
var 
largo miArray.length;

Array.
prototype.indexOf = function(x) {
    for(var 
i=0l=this.lengthi<li++)
        if( 
=== this[i] ) return true;
    return -
1;
}

function 
dameElemento() {
    
largoElegidos yaElegidos.length;
    if ( 
largoElegidos largo ) {
        
// termina con 'indice' siendo un índice de la matriz que todavía no fue elegido.
        
while ( yaElegidos.indexOf(indice Math.floorMath.random() * largo )) !== -);
        
yaElegidos[largoElegidos] = indice;
        return 
miArray[indice];
    }
    else {
        
//reiniciando
        
yaElegidos = new Array();
        return 
false;
    }



// hago la medicion de tiempo 10 veces para hacer una media:
var tiempos = [];
for(var 
t=0t<3t++) {
    var 
ini = new Date().getTime();
    do {
        var 
elem dameElemento();
    } while(
elem!==false);
    var 
fin = (new Date().getTime()-ini);
    
tiempos.push(fin);
}
// hago la media de tiempos:
var tardanza = eval( "("+tiempos.join("+")+") / "tiempos.length )
document.write("Tiempos: "+tiempos+" --> Tiempo medio: "+tardanza); 
Y, teniendo en cuenta que el array ha sido multiplicado por 4 en vez de por 5 que yo puse, la salida que he obtenido en las mismas condiciones es:
Tiempos: 3465,2744,3295 --> Tiempo medio: 3168



Así que no sé si lo estoy haciendo bien... pero la intuición me dice que sí (hay un for dentro de un while y...)



Ya tengo preparada la siguiente idea, pero a ver si a alguien se le ocurren más maneras...


Un saludo
__________________
- Haz preguntas inteligentes, y obtendrás más y mejores respuestas.
- Antes de postearlo Inténtalo y Búscalo.
- Escribe correctamente tus mensajes.
  #4 (permalink)  
Antiguo 12/11/2007, 08:09
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Re: Optimización: Escoger un elemento aleatorio de un array no escogido ya

Tal parece que indexOf es bastante pesada
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 00:00.