Shuffle un diccionario en Python
Este post fue migrado de un blog hecho con Wordpress. Si se ve mal, dejame un comentario y lo arreglo.
El módulo random
de Python tiene varias funciones muy útiles.
>>> import random
Cómo choice
, que permite elegir un elemento al asar de una secuencia:
>>> lista = [1, 2, 3, "hola", 'q', '$', 0] >>> random.choice(lista) 1 >>> random.choice(lista) 0 >>> random.choice(lista) 3 >>> random.choice(lista) 'q' >>> random.choice("Esta es una oración muy interesante") 'E' >>> random.choice((1,2,3,4)) 3
O shuffle
, que desordena una lista (in place, es decir que no retorna una lista desordenada sino que la misma es desordenada):
>>> random.shuffle(lista) >>> lista [3, 1, 0, 'hola', '$', 'q', 2] >>> texto = "Esto es una pruba con SHUFFLE" >>> random.shuffle(texto) Traceback (most recent call last): File "<stdin>", line 1, in ? File "/usr/lib/python2.4/random.py", line 262, in shuffle x[i], x[j] = x[j], x[i] TypeError: object does not support item assignment
Obviamente ni a tuplas ni a strings se puede aplicar esta función ya que esos dos tipos de datos son inmutables.
Me encontraba yo programando y se me ocurrió que podría desordenar (shuffle) un diccionario para lograr cierto efecto. ¿Cual sería la semántica de esto? Seguro se entenderá mejor con un ejemplo, dado el diccionario:
{0 : "cero", 1 : "uno", 2 : "dos"}
que tiene números como claves y strings como valores, luego de que se le aplique la función shuffle
random.shuffle(dicc)
Se obtendría por ejemplo:
{0 : "uno", 1 : "dos", 2 : "cero"}
Bien, probémoslo en el REPL de Python:
>>> from random import shuffle >>> lista = [1,2,3,4,5,6,7,8] >>> shuffle(lista) >>> lista [4, 1, 7, 8, 6, 2, 5, 3] >>> dicc = {} >>> for a in range(8): dicc[a] = a >>> dicc {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7} >>> shuffle(dicc) >>> dicc {0: 1, 1: 4, 2: 7, 3: 6, 4: 2, 5: 5, 6: 3, 7: 0}
Mmm, parece que funciona. ¿Qué dicen uds? El del último ejemplo no es en realidad el diccionario que uso en mi programa, sino que es más bien algo así:
>>> dicc = {(1,1): "primero", (1,2): "segundo", (2,2): "otro"}
Intentamos mezclarlo y..
>>> shuffle(dicc) Traceback (most recent call last): File "<stdin>", line 1, in ? File "/usr/lib/python2.4/random.py", line 262, in shuffle x[i], x[j] = x[j], x[i] KeyError: 2
¿Qué pasó? La respuesta a este raro comportamiento está en el código mismo de Python, en el módulo random
. En mi instalación de Python2.4 en Debian GNU/Linux lo encontramos en: /usr/lib/python2.4/random.py
def shuffle(self, x, random=None, int=int): """x, random=random.random -> shuffle list x in place; return None. Optional arg random is a 0-argument function returning a random float in [0.0, 1.0); by default, the standard random.random. """ if random is None: random = self.random for i in reversed(xrange(1, len(x))): # pick an element in x[:i+1] with which to exchange x[i] j = int(random() * (i+1)) x[i], x[j] = x[j], x[i]
Sólo de ver la implementación se nota que solo funcionará con listas. La siguiente es mi alternativa, una función shuffle_dict
que sirve para mezclar los elementos de un diccionario:
from random import choice def shuffle_dict(d): """Shuffle the d dict.""" for i in d.keys(): k = d.keys() k.remove(i) j = choice(k) d[i], d[j] = d[j], d[i]
Comentarios
Comments powered by Disqus