Python tworzy słownik list


214

Chcę utworzyć słownik, którego wartościami są listy. Na przykład:

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

Jeśli zrobię:

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

Dostaję błąd KeyError, ponieważ d [...] nie jest listą. W takim przypadku mogę dodać następujący kod po przypisaniu a w celu zainicjowania słownika.

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

Czy jest na to lepszy sposób? Powiedzmy, że nie znam kluczy, których będę potrzebować, dopóki nie będę w drugiej forpętli. Na przykład:

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

Alternatywą byłoby wówczas zastąpienie

d[scope_item].append(relation)

z

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

Jak najlepiej sobie z tym poradzić? Idealnie byłoby, gdyby dołączanie „po prostu działało”. Czy jest jakiś sposób, aby wyrazić, że chcę słownik pustych list, nawet jeśli nie znam każdego klucza przy pierwszym tworzeniu listy?

Odpowiedzi:


278

Możesz użyć 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
Inne słowniki w collectionsmodule również działają w ten sposób, na przykład collections.OrderedDict.
txsaw1,

2
O. To jest świetne. I nie musisz inicjować na „= []”. Dobry towar!
Wilmer E. Henao,

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

51

Możesz zbudować go ze zrozumieniem listy w następujący sposób:

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

A do drugiej części pytania użyj 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

Możesz użyć 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']}

Raczej dziwnie nazwana setdefaultfunkcja mówi: „Uzyskaj wartość za pomocą tego klucza lub jeśli tego klucza nie ma, dodaj tę wartość, a następnie zwróć”.

Jak słusznie zauważyli inni, defaultdictjest lepszym i bardziej nowoczesnym wyborem. setdefaultjest nadal przydatny w starszych wersjach Pythona (wcześniejszych niż 2.5).


2
To działa, ale zwykle lepiej jest użyć defaultdict, gdy jest dostępny.
David Z

@David, tak, setdefault nie był najwspanialszym projektem, przepraszam - nie jest to zawsze najlepszy wybór. Myślę jednak, że my (podmioty odpowiedzialne za Python) odkupiliśmy naszą zbiorową reputację dzięki kolekcjom.defaultdict ;-).
Alex Martelli,

@DavidZ, setdefault różni się od defaultdict, ponieważ jest bardziej elastyczny: w przeciwnym razie, jak określić różne wartości domyślne dla różnych kluczy słownika?
Alex Gidan

@AlexGidan To prawda, ale nie ma szczególnego związku z tym pytaniem.
David Z

Ta odpowiedź jest również przydatna, gdy potrzebujesz polecenia OragedDict i wartości domyślnej.
nimcap

2

Odpowiedź na twoje pytanie została już udzielona, ​​ale IIRC możesz zastąpić wiersze takie jak:

if d.has_key(scope_item):

z:

if scope_item in d:

To znaczy dodniesienia d.keys()w tej konstrukcji. Czasami defaultdictnie jest najlepszą opcją (na przykład, jeśli chcesz wykonać wiele wierszy kodu po elseskojarzeniu z powyższym if), a inskładnię uważam za łatwiejszą do odczytania.


2

Osobiście używam JSON do konwersji rzeczy na ciągi znaków i odwrotnie. Ciągi, które rozumiem.

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

łatwy sposób to:

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

print(d)
{'1': [1, ], '2':[2, ]}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.