Busqueda local

Loading

sábado, 12 de marzo de 2011

Random

Recientemente descubrí que lo que por mucho tiempo creí que era aleatorio, resulta no serlo. Así la clase Random, en realidad genera números pseudo-aleatorios, ya que en realidad usan una formula matemática, por lo que podría ser predecible, es algo que no me había afectado, y me había servidor en muchas situaciones; sin embargo en un proyecto reciente, no fue suficiente usar Random en .NET.
Probé desde lo más tradicional con la clase Random y el método Next hasta lo más moderno con LINQ, sin embargo mi problema no se solucionaba.
 

Requerimientos

El código debería generar una lista de preguntas, diferente para cada solicitud, a partir de un grupo de reactivos de una base de datos. La idea es generar exámenes con preguntas diferentes cada vez que alguien solicitara presentarlo. Esto quiere decir que a partir de la lista de preguntas almacenada en la base de datos, el sistema debe poder seleccionar un grupo diferente de pregunta, cada vez, no basta con presentar las mismas preguntas en diferente orden cada vez, si ese hubiera sido el caso, se podría solucionar con este ejemplo:
rand1
El resultado seria:
rand0
 

Analicemos

Si pudiéramos obtener un conjunto de preguntas del total de la base de forma aleatoria y si además pudiéramos obtener los elementos resultantes también de forma aleatoria mientras recorremos la colección usando un Foreach, aumentaríamos la posibilidad de presentar un examen diferente en cada ocasión.
 

Solución

Dividiremos el análisis en dos métodos:
  • Primer método: Obtener algunas preguntas de la base en forma aleatoria
  • Segundo método: Entregar las preguntas al Foreach de forma aleatoria.
 

Primer método

En vez de almacenar las preguntas en un List<T> podemos usar un Dictionary<Llave,Objeto>, de esta forma cada vez que agreguemos una pregunta a la colección, lo hacemos usando una llave generada de forma aleatoria; y al final la colección resultante la ordenamos por la llave, y obtenemos un grupo de preguntas. Con esto aumentamos las posibilidades de generar en verdad una lista aleatoria, cada vez:
rand2

Segundo método

Este método lo crearemos como una extensión de IEnumerable, y para reutilizarlo en otras ocasiones, lo crearemos genérico. En este método usáramos la clausula YIELD de la que hablamos en un post previo. Con lo cual nuestra función nos devolverá uno a uno los elementos para que sean usados en un Foreach. En esta ocasión usaremos un método diferente, creando un arreglo de números enteros a partir de un list, el cual servirá de índice para obtener los elementos del List usando una posición aleatoria dentro de un ciclo. En la última línea del código dentro del ciclo cambiamos el numero original en el arreglo de índices en la posición que enviamos, por el consecutivo del ciclo. Este pequeño truco impide que nuestro objeto enviado, se repita en un ciclo posterior:
rand3
Por último cambiamos nuestro código de pruebas:
rand4
El resultado seria:
randfinal

No hay comentarios:

Publicar un comentario