Python criando um dicionário de listas


214

Eu quero criar um dicionário cujos valores são listas. Por exemplo:

{
  1: ['1'],
  2: ['1','2'],
  3: ['2']
}

Se eu fizer:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d[j].append(i)

Eu recebo um KeyError, porque d [...] não é uma lista. Nesse caso, posso adicionar o seguinte código após a atribuição de a para inicializar o dicionário.

for x in range(1, 4):
    d[x] = list()

Existe uma maneira melhor de fazer isso? Digamos que não conheço as chaves que vou precisar até estar no segundo forciclo. Por exemplo:

class relation:
    scope_list = list()
...
d = dict()
for relation in relation_list:
    for scope_item in relation.scope_list:
        d[scope_item].append(relation)

Uma alternativa seria substituir

d[scope_item].append(relation)

com

if d.has_key(scope_item):
    d[scope_item].append(relation)
else:
    d[scope_item] = [relation,]

Qual a melhor forma de lidar com isto? Idealmente, anexar "apenas funcionaria". Existe alguma maneira de expressar que eu quero um dicionário de listas vazias, mesmo que eu não conheça todas as chaves ao criar a lista?

Respostas:


278

Você pode usar o defaultdict :

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = ['1', '2']
>>> for i in a:
...   for j in range(int(i), int(i) + 2):
...     d[j].append(i)
...
>>> d
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']})
>>> d.items()
[(1, ['1']), (2, ['1', '2']), (3, ['2'])]

1
Outros dicionários no collectionsmódulo também funcionam dessa maneira, por exemplo collections.OrderedDict.
txsaw1

2
Oh. Isso é ótimo. E você não precisa inicializar para '= []'. Coisa boa!
Wilmer E. Henao

1
NameError: name 'a' is not defined
S Andrew

51

Você pode construí-lo com compreensão de lista como esta:

>>> dict((i, range(int(i), int(i) + 2)) for i in ['1', '2'])
{'1': [1, 2], '2': [2, 3]}

E para a segunda parte da sua pergunta, use defaultdict

>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
        d[k].append(v)

>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

32

Você pode usar setdefault:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d.setdefault(j, []).append(i)

print d  # prints {1: ['1'], 2: ['1', '2'], 3: ['2']}

O nome bastante estranho setdefault função de diz "Obtenha o valor com essa chave ou, se essa chave não estiver lá, adicione esse valor e, em seguida, retorne".

Como outros já salientaram, defaultdicté uma escolha melhor e mais moderna. setdefaultainda é útil em versões mais antigas do Python (anteriores à 2.5).


2
Isso funciona, mas geralmente é preferível usar o comando default quando estiver disponível.
David Z

@ David, sim, o setdefault não era a parte mais brilhante do design, desculpe - quase nunca é a melhor escolha. Eu acho que nós (os comprometedores do Python) resgatamos nossa reputação coletiva com collections.defaultdict, embora ;-).
Alex Martelli

@DavidZ, setdefault é diferente do defaultdict, pois é mais flexível: por outro lado, como você especifica valores padrão diferentes para diferentes chaves do dicionário?
precisa saber é o seguinte

@AlexGidan Isso é verdade, mas não particularmente relevante para esta questão.
David Z

Esta resposta também é útil quando você precisa de um OrderedDict e um valor padrão.
Nimcap #

2

Sua pergunta já foi respondida, mas no IIRC você pode substituir linhas como:

if d.has_key(scope_item):

com:

if scope_item in d:

Ou seja, dreferências d.keys()nessa construção. Às vezes, defaultdictnão é a melhor opção (por exemplo, se você deseja executar várias linhas de código após o elseassociado ao descrito acima if), e acho a insintaxe mais fácil de ler.


2

Pessoalmente, eu apenas uso o JSON para converter as coisas em strings e vice-versa. Cordas eu entendo.

import json
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
mydict = {}
hash = json.dumps(s)
mydict[hash] = "whatever"
print mydict
#{'[["yellow", 1], ["blue", 2], ["yellow", 3], ["blue", 4], ["red", 1]]': 'whatever'}

1

maneira fácil é:

a = [1,2]
d = {}
for i in a:
  d[i]=[i, ]

print(d)
{'1': [1, ], '2':[2, ]}
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.