Comprensión del diccionario de Python

433

¿Es posible crear una comprensión de diccionario en Python (para las claves)?

Sin listas por comprensión, puede usar algo como esto:

l = []
for n in range(1, 11):
    l.append(n)

Podemos acortar este a una lista por comprensión: l = [n for n in range(1, 11)].

Sin embargo, digamos que quiero establecer las claves de un diccionario en el mismo valor. Puedo hacer:

d = {}
for n in range(1, 11):
     d[n] = True # same value for each

He intentado esto:

d = {}
d[i for i in range(1, 11)] = True

Sin embargo, obtengo un SyntaxErroren el for.

Además (no necesito esta parte, pero me pregunto), ¿puede configurar las claves de un diccionario para un montón de valores diferentes, como este:

d = {}
for n in range(1, 11):
    d[n] = n

¿Es esto posible con la comprensión de un diccionario?

d = {}
d[i for i in range(1, 11)] = [x for x in range(1, 11)]

Esto también plantea una SyntaxErroren el for.

1
  • 3
    Para información de futuros lectores: las matrices NumPy le permiten establecer varios elementos en un solo valor o lista de valores, de la manera que está tratando de hacer. Aunque si aún no tiene una razón para usar NumPy, probablemente no valga la pena solo por esta función. David Z 21/12/2015 a las 10:11
569

Hay comprensiones de diccionario en Python 2.7+ , pero no funcionan de la manera que estás intentando. Como una lista de comprensión, crean un nuevo diccionario; no puede usarlos para agregar claves a un diccionario existente. Además, debe especificar las claves y los valores, aunque, por supuesto, puede especificar un valor ficticio si lo desea.

>>> d = {n: n**2 for n in range(5)}
>>> print d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Si desea establecerlos todos en Verdadero:

>>> d = {n: True for n in range(5)}
>>> print d
{0: True, 1: True, 2: True, 3: True, 4: True}

Lo que parece estar pidiendo es una forma de configurar varias claves a la vez en un diccionario existente. No hay un atajo directo para eso. Puede realizar un ciclo como ya mostró, o puede usar la comprensión de un diccionario para crear un nuevo diccionario con los nuevos valores, y luego oldDict.update(newDict)fusionar los nuevos valores en el antiguo diccionario.

3
  • 15
    FWIW, dict.updatetambién puede aceptar un iterable de pares clave-valor como el dictconstructormgilson 24/01/2013 a las 18:19
  • 6
    Tenga en cuenta que si desea crear un diccionario con todos los valores iguales, utilice dict.fromkeys(). Entonces, para establecer todos los valores en True, use dict.fromkeys(range(5), True). Tenga cuidado, el valor no se copia , por lo que es posible que desee evitar esto cuando tenga un valor mutable; se compartirá entre todas las claves. Martijn Pieters 14 de mayo de 2016 a las 13:27
  • 2
    Nota: las claves pueden ser el resultado de un método así: { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Tanto se puede hacer en la misma expresión: { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }. Zaaier 24/04/2017 a las 15:27
156

Puedes usar el dict.fromkeysmétodo de clase ...

>>> dict.fromkeys(range(5), True)
{0: True, 1: True, 2: True, 3: True, 4: True}

Esta es la forma más rápida de crear un diccionario donde todas las claves se asignan al mismo valor.

Pero no , no usar esto con objetos mutables :

d = dict.fromkeys(range(5), [])
# {0: [], 1: [], 2: [], 3: [], 4: []}
d[1].append(2)
# {0: [2], 1: [2], 2: [2], 3: [2], 4: [2]} !!!

Si en realidad no necesita inicializar todas las claves, a defaultdictpodría ser útil también:

from collections import defaultdict
d = defaultdict(True)

Para responder a la segunda parte, una comprensión de dictados es justo lo que necesita:

{k: k for k in range(10)}

Probablemente no debería hacer esto, pero también podría crear una subclase de la dictcual funciona algo así como defaultdictsi anula __missing__:

>>> class KeyDict(dict):
...    def __missing__(self, key):
...       #self[key] = key  # Maybe add this also?
...       return key
... 
>>> d = KeyDict()
>>> d[1]
1
>>> d[2]
2
>>> d[3]
3
>>> print(d)
{}
1
  • Tenga en cuenta que en el caso de d = defaultdict(lambda: True), la lambda no es necesaria ya que True es (o no debería) ser mutable. rhbvkleef 22/01/18 a las 11:42
31
>>> {i:i for i in range(1, 11)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10}
27

Me gusta mucho el comentario de @mgilson, ya que si tienes dos iterables, uno que corresponde a las claves y el otro a los valores, también puedes hacer lo siguiente.

keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values))

donación

d = {'a': 1, 'b': 2, 'c': 3}

1
  • @binaryfunt Correcto, mi mal. LoMaPh 9/10/20 a las 19:15
14

Considere este ejemplo de contar la ocurrencia de palabras en una lista usando la comprensión del diccionario

my_list = ['hello', 'hi', 'hello', 'today', 'morning', 'again', 'hello']
my_dict = {k:my_list.count(k) for k in my_list}
print(my_dict)

Y el resultado es

{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}
2
  • 2
    Esto es interesante, aunque no el más eficiente, ya que contará claves como 'hola' varias vecesFuriousGeorge 8 de marzo de 2017 a las 15:17
  • Tenga en cuenta que esto es O (N ^ 2) e increíblemente lento incluso para tamaños de datos pequeños. Lo agregué a un código de producción y este fue un gran cuello de botella, pero ten en cuenta que esta respuesta es peligrosa. John D 2 de marzo a las 11:31
13

Use dict () en una lista de tuplas, esta solución le permitirá tener valores arbitrarios en cada lista, siempre que tengan la misma longitud

i_s = range(1, 11)
x_s = range(1, 11)
# x_s = range(11, 1, -1) # Also works
d = dict([(i_s[index], x_s[index], ) for index in range(len(i_s))])
1
  • 14
    Como nota al margen, esto es lo mismo qued = dict(zip(i_s,x_s))mgilson 24/01/2013 a las 18:12
11

El propósito principal de la comprensión de una lista es crear una nueva lista basada en otra sin cambiar o destruir la lista original.

En lugar de escribir

l = []
for n in range(1, 11):
    l.append(n)

o

l = [n for n in range(1, 11)]

deberías escribir solo

l = range(1, 11)

En los dos bloques de código superiores, está creando una nueva lista, iterando a través de ella y simplemente devolviendo cada elemento. Es solo una forma costosa de crear una copia de la lista.

Para obtener un nuevo diccionario con todas las claves configuradas con el mismo valor basado en otro dictado, haga esto:

old_dict = {'a': 1, 'c': 3, 'b': 2}
new_dict = { key:'your value here' for key in old_dict.keys()}

Recibes un SyntaxError porque cuando escribes

d = {}
d[i for i in range(1, 11)] = True

básicamente estás diciendo: "Establecer mi clave 'i para i en rango (1, 11)' en Verdadero" y "i para i en rango (1, 11)" no es una clave válida, es solo un error de sintaxis. Si dicta listas compatibles como claves, haría algo como

d[[i for i in range(1, 11)]] = True

y no

d[i for i in range(1, 11)] = True

pero las listas no se pueden usar con hash, por lo que no puede usarlas como claves de diccionario.

0

Una comprensión de diccionario es muy parecida a una comprensión de lista , pero obtenemos un diccionario al final, por lo que debemos asignar pares clave-valor en lugar de solo valores.

Digamos que tenemos una lista de usuarios, donde la información de cada usuario se almacena en una tupla. Entonces tenemos una lista con cuatro tuplas de usuario. En su interior, tienen una identificación, un número de identificación único para cada usuario, un nombre de usuario y una contraseña.

Por lo tanto, queremos crear una asignación de nombres de usuario a la información del usuario. Esto es algo que harás muy a menudo, especialmente si estás haciendo algo como aplicaciones web y cosas por el estilo.

users = [
    (0, "Bob", "password"),
    (1, "code", "python"),
    (2, "Stack", "overflow"),
    (3, "username", "1234"),
]

username_mapping = {user[1]: user for user in users}
userid_mapping = {user[0]: user for user in users}

print(username_mapping)

"""
Why can this be helpful?

Well, imagine you know a user's username,and you want to get their information out.
You just access, let's say, "Bob," in your username_mapping, and you've got the information out.
"""
print(username_mapping["Bob"])  # (0, "Bob", "password")

# -- Can be useful to log in for example --

username_input = input("Enter your username: ")
password_input = input("Enter your password: ")

_, username, password = username_mapping[username_input]

if password_input == password:
    print("Your details are correct!")
else:
    print("Your details are incorrect.")

Así que este es un ejemplo de cómo realizar algún tipo de inicio de sesión usando esta estructura aquí, esta comprensión de diccionario.

Esto es realmente útil porque le evita tener que hacer otro bucle for aquí, para asegurarse de que está usando el nombre de usuario correcto para su entrada.

-2

no se puede codificar una lista como esa. prueba esto en su lugar, usa tuplas

d[tuple([i for i in range(1,11)])] = True
0