Zrozumienie słownika Python


386

Czy w Pythonie można utworzyć słownikowe rozumienie (dla kluczy)?

Bez zrozumienia listy możesz użyć czegoś takiego:

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

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

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

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

Próbowałem tego:

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

Jednak dostaję SyntaxErrorna for.

Ponadto (nie potrzebuję tej części, tylko się zastanawiam), czy możesz ustawić klucze słownika na kilka różnych wartości, takich jak to:

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

Czy jest to możliwe dzięki zrozumieniu słownika?

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

To również podnosi SyntaxErrorna for.


3
Informacje dla przyszłych czytelników: tablice NumPy pozwalają ustawić wiele elementów na jedną wartość lub listę wartości, tak jak próbujesz to zrobić. Chociaż jeśli nie masz już powodu, aby korzystać z NumPy, prawdopodobnie nie warto tego robić.
David Z

Odpowiedzi:


520

W Pythonie 2.7+ istnieją wyrażenia słownikowe , ale nie działają one tak, jak próbujesz. Podobnie jak listy, tworzą nowy słownik; nie można ich używać do dodawania kluczy do istniejącego słownika. Musisz także określić klucze i wartości, choć oczywiście możesz podać wartość zastępczą, 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 na True:

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

Wygląda na to, że pytasz o sposób ustawienia wielu kluczy jednocześnie w istniejącym słowniku. Nie ma do tego bezpośredniego skrótu. Możesz albo zapętlić, jak już pokazałeś, lub użyć słownika, aby utworzyć nowy słownik z nowymi wartościami, a następnie oldDict.update(newDict)scalić nowe wartości ze starym.


15
FWIW, dict.updatemoże również akceptować iterowalne pary klucz-wartość, podobnie jak dictkonstruktor
mgilson

6
Zauważ, że jeśli chcesz utworzyć słownik z tymi samymi wartościami, użyj dict.fromkeys(). Aby ustawić wszystkie wartości True, użyj dict.fromkeys(range(5), True). Uważaj, wartość nie jest kopiowana , więc możesz tego uniknąć, jeśli masz zmienną wartość; zostanie udostępniony między wszystkimi kluczami.
Martijn Pieters

2
Uwaga: Klucze mogą być wynikiem sposobu, jak również: { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Oba mogą być wykonane w tym samym wyrażeniu: { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }.
Zaaier

151

Możesz użyć dict.fromkeysmetody klasowej ...

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

Jest to najszybszy sposób na utworzenie słownika, w którym wszystkie klucze są odwzorowane na tę samą wartość.

Ale czy nie skorzystać z tego modyfikowalnych obiektów :

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

Jeśli tak naprawdę nie musisz inicjować wszystkich kluczy, defaultdictprzydatne może być również:

from collections import defaultdict
d = defaultdict(True)

Aby odpowiedzieć na drugą część, zrozumienie dykta jest właśnie tym, czego potrzebujesz:

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

Prawdopodobnie nie powinieneś tego robić, ale możesz także utworzyć podklasę, dictktóra działa podobnie jak a, defaultdictjeśli przesłonisz __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)
{}

Zauważ, że w przypadku d = defaultdict(lambda: True)lambda nie jest wymagane, ponieważ prawda jest (lub nie powinna) być zmienna.
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

Naprawdę podoba mi się komentarz @mgilson, ponieważ jeśli masz dwie iterowalne, jedną, która odpowiada kluczom, a drugą 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ący

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


4
Używanie rozumienia {i:j for i in keys for j in values}
dyktu

11

Użyj dict () na liście krotek, to rozwiązanie pozwoli ci mieć dowolne wartości na każdej liście, o ile 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))])

12
Na marginesie, jest to to samo, cod = dict(zip(i_s,x_s))
mgilson 24.01.2013

10

Rozważ ten przykład liczenia występowania słów na liście przy użyciu słownika

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

I wynik jest taki

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

Jest to interesujące, choć nie najskuteczniejsze, ponieważ będziesz liczyć klucze takie jak „cześć” wiele razy
FuriousGeorge

7

Głównym celem zrozumienia listy jest utworzenie nowej listy opartej na innej, 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)]

powinieneś pisać tylko

    l = range(1, 11)

W dwóch najlepszych blokach kodu tworzysz nową listę, iterując ją i zwracając każdy element. To po prostu drogi sposób na utworzenie kopii listy.

Aby uzyskać nowy słownik ze wszystkimi kluczami ustawionymi na tę samą wartość na podstawie innego słownika, wykonaj następujące czynności:

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

Otrzymujesz błąd SyntaxError, ponieważ podczas pisania

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

w zasadzie mówisz: „Ustaw mój klucz” i dla i w zakresie (1, 11) na „Prawda”, a „i dla i w zakresie (1, 11)” nie jest prawidłowym kluczem, to tylko błąd składniowy. Jeśli dyktuje obsługiwane listy jako klucze, zrobiłbyś coś takiego

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

i nie

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

ale list nie można mieszać, więc nie można ich używać jako klawiszy dyktowania.


-3

nie możesz haszować takiej listy. spróbuj tego zamiast tego, używa krotek

d[tuple([i for i in range(1,11)])] = True
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.