2013-01-24 11 views
289

Czy można utworzyć słownik w języku Python (dla kluczy)?Python Dictionary Comprehension

Bez listowych, można użyć coś takiego:

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

Możemy skrócić ten do listy zrozumieniem: l = [n for n in range(1, 11)].

Powiedzmy jednak, że chcę ustawić klucze słownika na tę samą wartość. mogę zrobić:

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

Próbowałem to:

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

Jednak dostaję SyntaxError na for.

Dodatkowo (nie muszę tej części, ale po prostu zastanawiasz się), można ustawić klucze słownika, aby kilka różnych wartości, tak:

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

Czy to możliwe ze słownikiem zrozumieniem ?

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

Rodzi to również SyntaxError na for.

+1

Aby uzyskać informacje o przyszłych czytelnikach: tablice NumPy umożliwiają ustawienie wielu elementów do pojedynczej wartości lub listy wartości, tak jak to robisz. Chociaż jeśli nie masz jeszcze powodu używać NumPy, prawdopodobnie nie jest to warte tej właśnie funkcji. –

Odpowiedz

390

Istnieją dictionary comprehensions in Python 2.7+, ale nie działają tak, jak próbujesz. Tak jak ze zrozumieniem listy, tworzą nowy słownik nowy; nie można ich użyć do dodania kluczy do istniejącego słownika. Musisz również określić klucze i wartości, chociaż oczywiście możesz podać wartość dummy, jeśli chcesz.

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

Jeśli chcesz ustawić je wszystkie true:

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

Co wydaje się być pytanie o to sposób na ustawienie wielu klawiszy naraz na istniejącym słownika. Nie ma bezpośredniego skrótu do tego. Możesz albo zapętlić się tak, jak już pokazałeś, albo użyć słownika do zrozumienia, aby utworzyć nowy dict z nowymi wartościami, a następnie wykonać oldDict.update(newDict), aby scalić nowe wartości ze starym dyktem.

+10

FWIW, 'dict.update' może również akceptować iterowalne pary klucz-wartość, podobnie jak konstruktor' dict' – mgilson

+1

. Zauważ, że jeśli chcesz utworzyć słownik ze wszystkimi wartościami takimi samymi, użyj 'dict.fromkeys()'. Aby ustawić wszystkie wartości na "True", użyj 'dict.fromkeys (range (5), True)'. Uważaj, wartość * nie jest kopiowana *, więc możesz tego uniknąć, gdy masz zmienną wartość; zostanie udostępniony wszystkim kluczom. –

+1

Uwaga: klucze mogą być również wynikiem metody: '{n * 2: n dla n w zakresie (3)} => {0: 0, 2: 1, 4: 2}'. Oba można wykonać w tym samym wyrażeniu: '{n * 2: n * 3 dla n w zakresie (3)} => {0: 0, 2: 3, 4: 6}'. – Zaaier

136

Można użyć metody dict.fromkeys klasy ...

>>> dict.fromkeys(range(1, 11), True) 
{1: True, 2: True, 3: True, 4: True, 5: True, 6: True, 7: True, 8: True, 9: True, 10: True} 

To najszybszy sposób na stworzenie słownika gdzie odwzorować wszystkie klucze do tej samej wartości.

Bądź ostrożny korzystając z tego modyfikowalnych obiektów choć:

d = dict.fromkeys(range(10), []) 
d[1].append(2) 
print(d[2]) # ??? 

Jeśli nie faktycznie potrzeba zainicjować wszystkie klucze, o defaultdict może być przydatny także:

from collections import defaultdict 
d = defaultdict(lambda: True) 

Aby odpowiedzieć na drugą część, zrozumienie dyktowania jest tym, czego potrzebujesz:

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

Albo dla python2.6:

dict((k, k) for k in range(10)) 

Można również utworzyć sprytnego podklasy dict, który działa trochę jak defaultdict jeśli przesłonić __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) 
{} 

Neat.

+0

Należy zauważyć, że w przypadku 'd = defaultdict (lambda: True)', lambda nie jest wymagana, ponieważ True jest (lub nie powinna) być zmienna. – rhbvkleef

21
>>> {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} 
10

Zastosowanie dict() na listę krotek, rozwiązanie to pozwala mieć dowolne wartości w każdej listy, tak długo jak są one tej samej długości

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

Na marginesie, to jest to samo co 'd = dict (zip (i_s, x_s))' – mgilson

-2

nie można hash taka lista. spróbuj zamiast tego używa krotki

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

To nie robi wcale tego, co OP chciał ... –

6

Głównym celem wyrażeń listowych jest utworzyć nową listę w oparciu o inną bez zmiany lub zniszczenia oryginalnej listy.

Zamiast pisać

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

lub

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

należy napisać tylko

l = range(1, 11) 

w dwóch największych bloków kodu podczas tworzenia nowej listy, iteracja nim i po prostu zwracam każdy element. To tylko drogi sposób tworzenia kopii listy.

Aby uzyskać nowy słownik z wszystkich klawiszy przedstawionych do tej samej wartości opartej na innym dict, to zrobić:

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

Wysłaliśmy SyntaxError ponieważ kiedy piszesz

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

ty "Zasadniczo mówiąc:" Ustaw mój klucz "i dla i w zakresie (1, 11)" na True "i" i dla i w zakresie (1, 11) "nie jest prawidłowym kluczem, to tylko błąd składniowy. Jeśli dicts obsługiwane list jako kluczy, byś zrobił coś

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

i nie

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

ale listy nie są hashable, więc nie można ich używać jako klawisze DICT.

16

Bardzo podoba mi się komentarz @mgilson, ponieważ jeśli masz dwie iterables, jedną, która odpowiada klawiszom, a druga wartości, możesz również wykonać następujące czynności.

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

dając

D = { 'a' 1, 'b': 2 'C' 3}

9

Rozważmy przykład licząc występowanie słów na liście przy użyciu słownika zrozumieniem

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

a wynik jest

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

To jest interesujące, choć nie jest najbardziej wydajne jak wiele razy będziesz liczył klawisze takie jak "cześć" – FuriousGeorge