lunes, 17 de junio de 2013

Listas aleatorias (2 de 2)

Continuando con el artículo anterior, vamos a ordenar aleatoriamente una lista de nombres utilizando una macro. Nos servirá la macro empleada en la entrada Números aleatorios no repetidos, aunque habrá que hacer algunas adaptaciones.

Para comenzar, preparamos la lista de nombres en la "Hoja3":

Las columnas E, F y G serán columnas auxiliares. La lista aleatoria la pondremos en la columna C.
 
Necesitaremos pasarle a la macro la cantidad de nombres que tiene la lista. Por ello, la primera operación consistirá en realizar este cálculo y almacenarlo en E2.
 
En E2:
=CONTARA(B:B)-1     [Resultado: 8]
 
Accedemos al editor de VBA pulsando Alt + F11, seleccionamos Insertar + Módulo y escribimos el siguiente procedimiento:
 
Salimos del editor pulsando Alt + Q.
 
Para ejecutar esta macro lo más cómodo es poner un botón en la hoja. Se puede usar un Botón de Formulario (Programador + Insertar + Botón (control formulario)), un Botón ActiveX (Programador + Insertar + Botón de comando (control ActiveX)) o una forma cualquiera; por ejemplo, un Rectángulo redondeado.
 
Si elegimos la última opción, tendremos que acceder a Insertar + Formas + Rectángulo redondeado y dibujar un rectángulo en algún sitio cómodo de la hoja, como la celda C1. Redondeamos los laterales y, en Herramientas + Formato + Estilos de forma, escogemos el estilo que más nos guste. En el menú contextual, elegimos Modificar texto y escribimos: Nueva lista
 
Volvemos a abril el menú contextual, seleccionamos Asignar macro y, en el cuadro de diálogo correspondiente, seleccionamos Números_no_repetidos. Terminamos pulsando el botón Aceptar.
 
El botón ya es plenamente operativo. Hacemos clic sobre él y en la columna F aparecerá una lista de números no repetidos comprendidos entre 1 y 100000. 
 
Ahora, asignamos a cada número un orden jerárquico. Lo haremos en la columna G.
 
En G2:
=SI.ERROR(JERARQUIA.EQV(F2;$F:$F;1);"")     [Extendemos la fórmula hasta la fila 30]
 
Si prevemos que la lista va a ser muy grande, habrá que extender la fórmula mucho más abajo.
 
En C2:
=SI.ERROR(INDICE($B$2:$B$200;G2);"")     [Extendemos la fórmula hasta la fila 30]
 
Cada vez que pulsemos el botón, Excel devolverá una nueva lista. Si añadimos nuevos nombres, serán incorporados a la lista aleatoria en la próxima pulsación. Naturalmente, también podemos eliminar nombres.
 
En apariencia, la columna G es superflua. Podríamos haber diseñado la macro de manera que generara números aleatorios no repetidos comprendidos entre 1 y el valor de la celda E2. De ese modo, conseguiríamos directamente en la columna F una lista aleatoria similar a la que hemos obtenido en la columna G
 
La macro sería ésta:
 
También habría que modificar ligeramente la fórmula de C2:
 
En C2:
=SI(F2<>"";INDICE($B$2:$B$200;F2);"")
 
La hoja quedaría de este así:
 
Si esta macro resuelve el problema con una columna auxiliar menos, ¿no sería lógico utilizarla y descartar la anterior?
 
La verdad es que la última macro puede dar problemas cuando la lista tiene muchos nombres. Supongamos que la lista tiene 1.000 nombres. El bucle Do While... Loop debe generar 1.000 números al azar comprendidos entre 1 y 1.000, todos diferentes y guardarlos en la matriz número(). Se comprende que muchas veces el número generado ya exista y, en consecuencia, tendrá que descartarlo y volver a generar otro. Sin embargo, si le damos la opción de generar 1.000 números elegidos entre un abanico de números muchísimo mayor (por ejemplo, entre 1 y 100.000), la posibilidad de que un número generado no haya salido anteriormente será mucho mayor y los descartes serán, en consecuencia, mucho menores. El tiempo de ejecución de la macro disminuirá en la misma proporción. Por si esto no fuera suficiente, la segunda macro se cuelga cuando se trabaja con listas grandes.
 
La conclusión es clara: si no quieres problemas, usa la primera macro.
 
¿Qué ocurre si en la lista hay nombres repetidos? Nada raro. Cualquiera de las dos macros genera números diferentes, por lo que la función INDICE apuntará siempre a filas distintas. A esta función no le importa lo que haya escrito en una celda; simplemente, lo lee y lo copia en la columna C.
 
 
 
 

No hay comentarios:

Publicar un comentario