Autor Tema: Trocitos de código  (Leído 3454 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado mxgxw

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 5665
  • Starlet - 999cc
    • mxgxw
Trocitos de código
« : diciembre 22, 2010, 08:18:20 am »
Bueno srs, abro este tema donde pienso poner soluciones a problemas sencillos que generalmente nos quiebran la cabeza jejeje aunque sea un par de minutos.

Se que todos nos encontramos con estos problemas día a día y a veces encontramos una solución sencilla y práctica, así que si quieren compartir su solución pueden ponerla en este tema:

Problema:

Citar
De un número cualquiera obtener el dígito en cualquier posición especificada. Ejemplo: Para el número 124 crear un codigo que me devuelva 1, 2 y 4 de manera separada sin utilizar funciones de cadena.

Solución:

Código: [Seleccionar]
var numero = 123456;
var primero = Math.floor((numero/1)%10); // devuelve 6
var primero = Math.floor((numero/10)%10); // devuelve 5
var primero = Math.floor((numero/100)%10); // devuelve 4
var primero = Math.floor((numero/1000)%10); // devuelve 3
var primero = Math.floor((numero/10000)%10); // devuelve 2
var primero = Math.floor((numero/100000)%10); // devuelve 1

Como funcion:
Código: [Seleccionar]
/* USO
 * [123456.5 4] Numero
 *  |||||| | |
 * [543210-1-2] Posicion
 * EJEMPLO:
 * obtenerEnPosicion(14.25,-2) // devuelve 5
 * obtenerEnPosicion(14.25,1) // devuelve 1
 */
function obtenerEnPosicion(numero,posicion) {
    return Math.floor((numero/Math.pow(10,posicion))%10);
}



Desconectado mxgxw

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 5665
  • Starlet - 999cc
    • mxgxw
Re: Trocitos de código
« Respuesta #1 : marzo 17, 2011, 05:18:58 pm »
Problema:

Citar
Tiene un numero limitado de opciones que quiere que aparescan al azar (A,B,C,D,E). Sin embargo quiere forzar la probabilidad de aparición de cada una de las mismas. Por ejemplo desea que la A aparesca el 50% de las veces, la B, C y D desea que aparescan un 10% de las veces y la E que aparesca un 20% de las veces. Sin que sea posible determinar con certeza que letra va a aparecer.

Desarrolle un código que permita establecer la probabilidad de aparición de cada item de la lista.

Solución:
Citar
Vamos a asumir que tenemos un casillero con 10 posiciones.
Vamos a asumir también que estos casilleros se abren uno a la vez de manera aleatoria, es decir no podemos saber que casillero se va a abrir.
Vamos a asumir que dentro de cada casillero hay un cartón con una letra pintada encima. Las letras son A, B, C, D y E.

Si yo quiero, que la probabilidad de que aparesca una A, al abrir el casillero sea del 50%, entonces debo asegurarme que de los 10 casilleros 5 tengan dentro de sí la letra A.

Visto de forma numérica la cantidad de los cartones correspondería a la siguiente:

5 de 10 cartones pintados con la A
1 de 10 cartones pintados con la B
1 de 10 cartones pintados con la C
1 de 10 cartones pintados con la D
2 de 10 cartones pintados con la E

En total tenemos 10 cartones que repartiremos dentro de los 10 casilleros. El orden en que los repartamos no importa ya que como el casillero se abre al azar habremos establecido la probabilidad de aparición de cada letra.

¿Como haremos esto en código?

Primero, necesitamos establecer una lista que contenga los elementos que queremos junto con su probabilidad de aparición. Esto lo podemos hacer en javascript creando un array de objetos que contengan el valor con su respectiva probabilidad:

Código: [Seleccionar]
var cartones =
Array(
    { valor:"A", probabilidad: (5/10) },
    { valor:"B", probabilidad: (1/10) },
    { valor:"C", probabilidad: (1/10) },
    { valor:"D", probabilidad: (1/10) },
    { valor:"E", probabilidad: (2/10) }
    );

Antes de continuar es muy importante aclarar que las probabilidades en total tienen que sumar 100%. No puede ser ni más ni menos, aquí tenemos que tener cuidado en ajustar las probabilidades de manera acorde a como nosotros querramos.

Lo segundo es un poco más sencillo pero un poco difícil de explicar....

La funcion Math.random(), nos devuelve un valor pseudo aleatorio entre 0 y 1. Si leen la analogía de los casilleros nosotros tenemos que asignar los espacios correspondientes a la probabilidad.

Si tuvieramos que verificar este "casillero" con if el codigo para seleccionar al azar nos quedaría algo así:

Código: [Seleccionar]
function obtenerLetra() {
  var random = Math.random();
  if(random>0 && random<(5/10)) {
    return "A"; // Devuelve A si random entre 0 y 0.5
  } else if(random>(5/10) && random<( 5/10 + 1/10 )) {
    return "B"; // Devuelve B si random entre 0.5 y 0.6
  } else if(random>( 5/10 + 1/10 ) && random<( 5/10 + 1/10 + 1/10 )) {
    return "C"; // Devuelve C si random entre 0.6 y 0.7
  } else if(random>( 5/10 + 1/10 + 1/10  ) && random<( 5/10 + 1/10 + 1/10 + 1/10 )) {
    return "D"; // Devuelve D si random entre 0.7 y 0.8
  } else if(random>( 5/10 + 1/10 + 1/10 + 1/10 ) && random<(5/10 + 1/10 + 1/10 + 1/10 + 2/10)) {
    return "E"; // Devuelve E si random entre 0.8 y 1.0
  } else if
}

Pero mx.. preguntaran algunos. ¿Porqué los casilleros se llenan en el orden de las letras?

Respuesta: Realmente aquí el orden no importa, asumimos que el numero devuelto por Math.random(), es lo suficientemente aleatorio, es decir cualqueir valor entre 0 y 1 tiene la misma probabilidad de aparecer.

Al hacer la seleccion de valores por rangos lo que estamos haciendo es aumentando la probabilidad de una opción especifica de aparecer. Sin embargo la letra que aparece siempre es aleatoria ya que en teoría no tenemos forma de determinar que letra aparecerá, únicamente podemos saber la probabilidad de que aparesca.

Un uso interesante para esta funcion es por ejemplo, en un juego de tragaperras que querramos que el usuario solo gane un 10% de las veces.

Si lo quieren como funcion, el código sería algo así.
Código: [Seleccionar]
function obtenerLetraProbabilidad() {
  var random = Math.random();
  var base=0;
  for(var i=0;i<items.length;i++) {
      if(random>=base && random<(base+items[i].probabilidad)) {
          return items[i].valor; // devuelve valor si esta dentro del rango especificado
      } else {
          base += items[i].probabilidad;
      }
  }
}

P.D.: Ya ven que sirven de algo las clases de estadística en la U fksjad lfja hfkjfdasda
« Última Modificación: marzo 17, 2011, 05:28:17 pm por mxgxw »


Desconectado JaiMe

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 1485
  • λ | h+
Re: Trocitos de código
« Respuesta #2 : marzo 17, 2011, 07:20:10 pm »
Excenlente,

unas observaciones.

Código: [Seleccionar]
var items =
Array(
    { valor:"A", probabilidad: (5/10) },
    { valor:"B", probabilidad: (1/10) },
    { valor:"C", probabilidad: (1/10) },
    { valor:"D", probabilidad: (1/10) },
    { valor:"E", probabilidad: (2/10) }
);

function obtenerLetraProbabilidad() {
  var random = Math.random();
  var base=0;
  for(var i=0;i<items.length;i++) {
      if(random>=base && random<(base+items[i].probabilidad)) {
          return items[i].valor; // devuelve valor si esta dentro del rango especificado
      } else {
          base += items[i].probabilidad;
      }
  }
}

console.log( obtenerLetraProbabilidad() );


Debido a lexical scoping durante compilation time La funcion obtenerLetraProbabilidad() sabe sobre
la existencia del array items un nivel arriba. Esto puede dar problemas cuando la complexidad del codigo aumenta.
(http://blog.dreasgrech.com/2009/12/lexical-scoping-in-javascript.html). Para evitar futuras molestias, podriamos
hacer los siguientes cambios

a) Pasar items como argumento a la funcion obtenerLetraProbabilidad()


Código: [Seleccionar]
console.log('Implementaciones\n');
console.log('*************** 1)');
// declaration
function obtenerLetraProbabilidad2(items) {
  var random = Math.random();
  var base=0;
  for(var i=0;i<items.length;i++) {
      if(random>=base && random<(base+items[i].probabilidad)) {
          return items[i].valor; // devuelve valor si esta dentro del rango especificado
      } else {
          base += items[i].probabilidad;
      }
  }
}
// call
var letra = obtenerLetraProbabilidad2(items)
console.log(letra);

Tambien podriamos ejecutarlo de la siguinete manera

Código: [Seleccionar]
letra = obtenerLetraProbabilidad2([
    { valor:"F", probabilidad: (5/10) },
    { valor:"G", probabilidad: (1/10) },
    { valor:"H", probabilidad: (1/10) },
    { valor:"I", probabilidad: (1/10) },
    { valor:"J", probabilidad: (2/10) }
]);
console.log(letra);


b) Construir una factory function que abstraiga la complejidad. Aqui ya estamos hablando de construir APIs. Esto nos
permitiria modificar el estado de la collecion que mantene nuestras letras y sus probabilidades, al mismo tiempo
ofrecemos a nuestros usuarios un API publica y evitamos que modifiquen la collecion directamente. 


Código: [Seleccionar]
var probabilityBuilder = function(){
var items = []; // array

return{
add: function(v, w) {
items.push({
valor: v,
weight: w
});
},
get:function(){
var random = Math.random();
  var base=0;
  for(var i=0;i<items.length;i++) {
      if(random>=base && random<(base+items[i].weight/this.total())) {
          return items[i].valor; // devuelve valor si esta dentro del rango especificado
      } else {
          base += items[i].weight/this.total();
      }
  }
},
total: function(){
var total = 0;
for(var i=0, t=items.length; i<t;i++){
total += items[i].weight;
}
return total;
},
debug: function(){
console.log('<Debug=========')
console.log(items);
console.log('totalWeight: ' + this.total());
console.log('=========Debug/>')
}
}
}();

console.log('\n*************** 2)');

probabilityBuilder.add('A',5);
probabilityBuilder.add('B',1);
probabilityBuilder.add('C',1);
probabilityBuilder.add('D',1);
probabilityBuilder.add('E',2);

var letra = probabilityBuilder.get();
probabilityBuilder.debug();
console.log(letra);

Tambien simplificamos la manera de ingresar probabilidades, el usuario solo tendria que ingresar el weight de la
letra, las probabilidades se ajustarian de acuerdo a las letras agregadas

Código: [Seleccionar]
console.log('Agregando letras');
probabilityBuilder.add('F',1);
probabilityBuilder.add('G',4);
probabilityBuilder.add('H',5);
probabilityBuilder.add('I',3);

var letra = probabilityBuilder.get();
probabilityBuilder.debug();
console.log(letra);

Eso es todo lo que queria agregar :-)

Oh, y el output:



Codigo aca
https://gist.github.com/875470
"Unless you try to do something beyond what you have already mastered, you will never grow."
― Ralph Waldo Emerson

Desconectado mxgxw

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 5665
  • Starlet - 999cc
    • mxgxw
Re: Trocitos de código
« Respuesta #3 : marzo 18, 2011, 10:52:42 am »

Ahora lo único que necesitaríamos es hacer que la A aparezca más veces. Pero no solo eso, sino que también distribuir las A lo mejor posible en la cadena para que tenga más puntos de probabilidad de salir (algo que requeriría algoritmos de distribución si se quieren crear tablas con otros datos en tiempo de ejecución, que tengan el mismo grado de balance):


Una pequeña correccion.... Eso que has puesto no es cierto.

Si asumis que la fuente aleatoria es realmente aleatória entonces la probabilidad de aparición de cualquier cifra entre 0 y 1 es siempre la misma. No importa el orden de las opciones sino la cantidad de las mismas en realación con el total.

Es decir, el orden de colocación de las letras no altera la probabilidad de aparicion de las mismas ya que si la probabilidad de selección de un item fuera afectada por la posición del item en el arreglo, entonces esto sería un indicador que la fuente no es realmente aleatoria o de que hay otra variable que modifica la probabilidad de selección.

Imagina que tienes un dado balanceado perfectamente. Vos podes distribuir los números como querras en las caras del mismo, sin embargo la probabilidad de aparición de cada número siempre será 1/6.

Creo que has confundido mi ejemplo con el de una tombola de sorteo, para la analogía de la tombola es necesario revolver el contenido porque la aleatoriedad la genera el proceso de mezclado y la selección depende de la posición, es decir los cartones que esten más arriba son los que tienen más probabilidad de ser seleccionados.

Para el caso de los casilleros, imaginate que el casillero que se abre se selecciona antes de tener acceso a los mismos, así que no hay ninguna variable que condicione cual se abrirá primero en base a la posición del mismo.

Ahora. Hay que recordar que la fuente de aleatoriedad de las computadoras es pseudo-aleatoria, esto es, que utiliza un algoritmo para generar una serie de números utilizando una "semilla". La salida de estos números aunque no es perfectamente aleatoria, si le aplicas un análisis estadístico tiene suficiente "aleatoriedad" como para considerarla como tal.
« Última Modificación: marzo 18, 2011, 12:51:48 pm por mxgxw »