Comprensión del diccionario de Python

386

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

Sin listas de 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, supongamos que quiero establecer las claves de un diccionario con 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, me sale un SyntaxErroren el for.

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

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

¿Es esto posible con una comprensión de diccionario?

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

Esto también plantea un SyntaxErroren el for.

Rushy Panchal
fuente
3
Para la información de futuros lectores: las matrices NumPy le permiten configurar múltiples elementos en un solo valor o lista de valores, de la manera que está tratando de hacerlo. Aunque si aún no tiene una razón para usar NumPy, probablemente no valga la pena solo por esta función.
David Z

Respuestas:

520

Hay comprensiones de diccionario en Python 2.7+ , pero no funcionan del modo en que lo está 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 True:

>>> 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 teclas a la vez en un diccionario existente. No hay un atajo directo para eso. Puede hacer un bucle como ya mostró, o puede usar una comprensión del diccionario para crear un nuevo dict con los nuevos valores y luego oldDict.update(newDict)fusionar los nuevos valores en el antiguo dict.

BrenBarn
fuente
15
FWIW, dict.updatetambién puede aceptar un iterable de pares clave-valor al igual que el dictconstructor
mgilson
66
Tenga en cuenta que si desea crear un diccionario con todos los valores iguales, use dict.fromkeys(). Entonces, para establecer todos los valores True, use dict.fromkeys(range(5), True). 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
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
151

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 realmente 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 dict 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 dictque funcione de manera similar a una defaultdictanulación __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)
{}
mgilson
fuente
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
28
>>> {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}
NPE
fuente
22

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

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

dando

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

ehontz
fuente
44
Usando Dict Comprehension:{i:j for i in keys for j in values}
LoMaPh
11

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))])
Bryan
fuente
12
Como nota al margen, esto es lo mismo qued = dict(zip(i_s,x_s))
mgilson el
10

Considere este ejemplo de contar la aparición 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}
adonese
fuente
Esto es interesante, aunque no es el más eficiente, ya que
contarás
7

El objetivo 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 en el mismo valor basado en otro dict, haga esto:

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

Estás recibiendo 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" e "i para i en rango (1, 11)" no es una clave válida, es solo un error de sintaxis. Si dicta las 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 compartir, por lo que no puede usarlas como claves dict.

Bonifacio2
fuente
-3

no puedes hacer una lista como esa. intente esto en su lugar, usa tuplas

d[tuple([i for i in range(1,11)])] = True
Aditya Sihag
fuente