Compreensão de dicionário Python


386

É possível criar uma compreensão de dicionário em Python (para as chaves)?

Sem compreensão de lista, você pode usar algo como isto:

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

Nós podemos encurtar este a uma compreensão da lista: l = [n for n in range(1, 11)].

No entanto, digamos que desejo definir as chaves de um dicionário com o mesmo valor. Eu posso fazer:

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

Eu tentei isso:

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

No entanto, eu recebo um SyntaxErrorno for.

Além disso (eu não preciso desta parte, mas apenas imaginando), você pode definir as chaves de um dicionário com vários valores diferentes, como este:

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

Isso é possível com a compreensão de um dicionário?

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

Isso também gera um SyntaxErrorno for.


3
Para informações de futuros leitores: as matrizes NumPy permitem definir vários elementos em um único valor ou lista de valores, da maneira que você está tentando fazer. Embora se você ainda não tem um motivo para usar o NumPy, provavelmente não vale a pena apenas por esse recurso.
David Z

Respostas:


520

Existem compreensões de dicionário no Python 2.7+ , mas elas não funcionam da maneira que você está tentando. Como uma compreensão de lista, eles criam um novo dicionário; você não pode usá-los para adicionar chaves a um dicionário existente. Além disso, é necessário especificar as chaves e os valores, embora, é claro, você possa especificar um valor simulado, se quiser.

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

Se você deseja defini-los todos como True:

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

O que você parece estar pedindo é uma maneira de definir várias chaves ao mesmo tempo em um dicionário existente. Não há atalho direto para isso. Você pode fazer um loop como você já mostrou, ou usar uma compreensão de dicionário para criar um novo ditado com os novos valores e, em seguida, fazer oldDict.update(newDict)a mesclagem dos novos valores no antigo ditado.


15
FWIW, dict.updatetambém pode aceitar um iterável de pares chave-valor como o dictconstrutor
mgilson

6
Observe que se você criar um dicionário com todos os valores iguais, use dict.fromkeys(). Portanto, para definir todos os valores True, use dict.fromkeys(range(5), True). Cuidado, o valor não é copiado ; portanto, você pode evitar isso quando tiver um valor mutável; será compartilhado entre todas as chaves.
Martijn Pieters

2
Nota: as teclas podem ser o resultado de um método assim: { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Tanto pode ser feito na mesma expressão: { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }.
precisa saber é o seguinte

151

Você pode usar o dict.fromkeysmétodo de classe ...

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

Essa é a maneira mais rápida de criar um dicionário onde todas as chaves são mapeadas para o mesmo valor.

Mas não não usar isso com objetos mutáveis :

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

Se você realmente não precisa inicializar todas as chaves, a também defaultdictpode ser útil:

from collections import defaultdict
d = defaultdict(True)

Para responder à segunda parte, uma compreensão de ditado é exatamente o que você precisa:

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

Você provavelmente não deve fazer isso, mas também pode criar uma subclasse dictque funciona como um defaultdictse você substituir __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)
{}

Observe que, no caso de d = defaultdict(lambda: True), o lambda não é necessário, pois True é (ou não deveria) ser mutável.
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}

22

Gosto muito do comentário do @mgilson, já que se você tiver dois iterables, um que corresponda às chaves e o outro aos valores, também poderá fazer o seguinte.

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

dando

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


4
Usando a compreensão de {i:j for i in keys for j in values}
dict

11

Use dict () em uma lista de tuplas, esta solução permitirá que você tenha valores arbitrários em cada lista, desde que tenham o mesmo comprimento

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))])

12
Como uma observação lateral, isso é a mesma coisa qued = dict(zip(i_s,x_s))
mgilson

10

Considere este exemplo de contagem da ocorrência de palavras em uma lista usando compreensão de dicionário

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

E o resultado é

{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}

Isso é interessante, embora não o mais eficiente como você vai estar contando chaves como 'Olá' várias vezes
FuriousGeorge

7

O principal objetivo de uma compreensão de lista é criar uma nova lista com base em outra, sem alterar ou destruir a lista original.

Em vez de escrever

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

ou

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

você deve escrever apenas

    l = range(1, 11)

Nos dois blocos de código principais, você está criando uma nova lista, iterando através dela e retornando cada elemento. É apenas uma maneira cara de criar uma cópia da lista.

Para obter um novo dicionário com todas as chaves definidas para o mesmo valor com base em outro ditado, faça o seguinte:

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

Você está recebendo um SyntaxError porque quando escreve

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

você está basicamente dizendo: "Defina minha chave 'i para i no intervalo (1, 11)' como True" e "i para i no intervalo (1, 11)" não é uma chave válida, é apenas um erro de sintaxe. Se ditar listas suportadas como chaves, você faria algo como

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

e não

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

mas as listas não são hasháveis; portanto, você não pode usá-las como chaves dict.


-3

você não pode misturar uma lista como essa. tente fazer isso, usa tuplas

d[tuple([i for i in range(1,11)])] = True
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.