miércoles, 26 de mayo de 2010

Escogiendo números al azar o RTFA

Hoy un mensaje breve y al grano, para ilustrar la importancia de perder un rato investigando el API de Java, que es muy rico y uno de las mejores cosas que tiene el lenguaje (vale, no es perfecto y tiene algunas cagadas *ehem* Date *ehem* pero te da muchas cosas hechas).

El problema planteado es el típico que sale habitualmente en foros de "escoger X números entre Y posibles de forma aleatoria y sin repeticiones". Una especie de Lotería Primitiva, vamos. Las soluciones habituales suelen tender a usar Random para generar números de forma aleatoria y comprobar si el número ya lo tenemos o no, solución que por probabilidad no podemos asegurar cuanto tiempo se tirará ejecutándose, o meter todos los números en una lista, escogerlos aleatoriamente e irlos borrando etc.

La segunda opción no es mala y al menos es "determinista*", pero si perdemos 5 minutos en el API de las colecciones, podemos llegar a esto (como extra devolvemos los números ordenados):

/**
   * Devuelve numberCount números de entre 1 y
   *  maxNumber escogidos de forma aleatoria y
   * ordenados.
   * 
   * @param maxNumber
   * @param numberCount
   * @return La lista ordenada con los números seleccionados aleatoriamente.
   */
  private static List selectRandomNumbers(int maxNumber, int numberCount)
  {
    List numberList = new LinkedList();
    for (int i = 1; i <= maxNumber; i++)
    {
      numberList.add(i); //**
    }
    Collections.shuffle(numberList);
    numberList =
      numberList.subList(0, numberCount);
    Collections.sort(numberList);
    return numberList;
  }
Y eso es todo. Dos métodos de Collections y uno de List hacen todo el trabajo y no tenemos que preocuparnos de nada. Los ingenieros del JDK se preocuparán de optimizar ese código y nosotros podemos dedicarnos al “core” de nuestro negocio. La moraleja es... no hagas tú el trabajo si alguien ya lo ha hecho por ti. O como decía Mulder cuando programaba en Java... "La verdad, está en el API" ;P

*: Determinista en cuanto sabemos el flujo de ejecución que va a seguir sin depender del azar.
**: Sí, estoy metiendo primitivas en una lista, cosa que solo funciona gracias al mágico autoboxing de las últimas versiones de Java y que no me gusta, pero para este caso el compilador escribiría el mismo código, así que...

Happy coding! EJ

No hay comentarios:

Publicar un comentario