previous up next hi end end

11. Slovníky

  1. Slovníkové operace
  2. Slovníkové metody
  3. Alias a kopírování
  4. Řídké matice
  5. Počítání písmen
  6. Glosář
  7. Cvičení

Dosud poznané složené datové typy – řetězce, seznamy a entice – jsou sekvence, které používají celá čísla jako indexy pro přístup jednotlivým položkám.

Slovníky jsou odlišný složený datový typ. Jsou rovněž složeny z položek, ale každá položka se skládá z dvojice klíč - hodnota. Klíčem může být pouze neměnitelný datový typ, hodnotou libovolný datový typ.

Jako příklad vytvoříme slovník pro překlad anglických slov do španělštiny. Klíči u tohoto slovníku budou řetězce.

Začneme tak, že vytvoříme prázdný slovník, do kterého přidáme párové položky. Prázdný slovník se označuje {}:

>>> eng2sp = {}
>>> eng2sp['one'] = 'uno'

>>> eng2sp['two'] = 'dos'

První přiřazení vytvoří prázdný slovník s názvem eng2sp, další přiřazení přidávají nové párové položky. Aktuální hodnotu slovníku můžeme vytisknout obvyklým způsobem:

>>> print(eng2sp)
{'two': 'dos', 'one': 'uno'}

Párové položky jsou oddělené čárkami. Každý pár obsahuje klíč a hodnotu, oddělenou dvojtečkou. Python používá složitý algorimus pro zařazení páru do slovníku. Pro nás bude jednodušší předpokládat, že toto řazení je nepředvídatelné.

Jiným způsobem vytvoříme slovník tak, že přímo zadáme seznam párů klíč-hodnota:

>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}

Na pořadí při zapisování párů nezáleží. Hodnoty ve slovníku jsou přístupné prostřednictvím klíčů, nikoliv indexů a o pořadí se tedy nemusíme starat.

Takto použijeme klíče k vyhledání odpovídající hodnoty:

>>> print(eng2sp['two'])
'dos'

Klíč 'two' zprostřekuje hodnotu 'dos'

11.1 Slovníkové operace

Příkaz del odstraní dvojici klíč-hodnota ze slovníku. Následující slovník na příklad obsahuje jména různého druhu ovoce a jeho množství na skladě:

>>> inventory = {'apples': 430, 'bananas': 312, 'pears': 217, 'oranges': 525}
>>> print(inventory)
{'oranges': 525, 'apples': 430, 'pears': 217, 'bananas': 312}

Když někdo skoupí všechny hrušky, můžeme tento vstup ze slovníku vyjmout:

>>> del inventory['pears']
>>> print(inventory)
{'apples': 430, 'oranges': 525, 'bananas': 312}

Nebo očekáváme-li, že hrušky zase budou, můžeme pouze změnit hodnotu spojenou s hruškami:

>>> inventory['pears'] = 0
>>> print(inventory)
{'apples': 430, 'bananas': 312, 'oranges': 525, 'pears': 0}

U slovníku můžeme také použít funkci len, která vrací počet dvojic klíč-hodnota:

>>> len(inventory)
4

11.2 Slovníkové metody

Slovníky mají řadu užitečných vestavěných metod, jejichž seznam získáme známou funkcí dir():

>>> dir(dict)
['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop',
'popitem', 'setdefault', 'update', 'values', ... ]

Metoda keys přijme slovník a vrátí seznam jeho klíčů:

>>> eng2sp.keys()
dict_keys(['one', 'three', 'two'])

Tato forma tečkové notace uvádí jméno metody keys a jméno objektu eng2sp, na němž má být metoda použita. Prázdné závorky naznačují, že tato metoda nepřijímá žádné parametry.

Volání metody se nazývá invokace; v tomto případě bychom řekli, že invokujeme metodu keys pro objekt ger2eng.

Metoda values je podobná; vrací seznam hodnot ve slovníku:

>>> eng2sp.values()
dict_values(['uno', 'tres', 'dos'])

Metoda items vrací obojí formou seznamu entic:

>>> eng2sp.items()
dict_items([('one', 'uno'), ('three', 'tres'), ('two', 'dos')])

Syntaxe poskytuje užitečnou informaci o typech. Hranaté závorky naznačují, že jde o seznam. Oblé závorky naznačují, že položkami seznamu jsou entice.

Přítomnost klíče ve slovníku lze ověřit idiomem s klíčovým slovem in:

>>> "one" in eng2sp
True
>>> "deux" in eng2sp
False

11.3 Alias a kopírování

Protože jsou slovníky měnitelné, musíme si dát pozor na aliasování. Kdykoliv dvě proměnné odkazují ke stejnému objektu, jeho změna prostřednictvím jedné proměnné je sdílena i druhou proměnnou.

Chceme-li měnit slovník a přitom si zachovat kopii originálu, použijeme metodu copy. Například, opposites je slovník, který obsahuje dvojice protikladů:

>>> opposites = {'up': 'down', 'right': 'wrong', 'true': 'false'}
>>> alias = opposites
>>> copy = opposites.copy()

Proměnné alias a opposites odkazují na stejný objekt, proměnná copy odkazuje na čerstvou kopii téhož slovníku. Upravíme-li alias, změní se i opposites:

>>> alias['right'] = 'left'
>>> opposites['right']
'left'

Když naproti tomu upravíme copy, tak se opposite nezmění:

>>> copy['right'] = 'privilege'
>>> opposites['right']
'left'

11.4 Řídké matice

V odstavci 9.2 jsme použili seznam seznamů k prezentaci matice. To je dobrý způsob pro matice s převážně nenulovými hodnotami, uvažme však řídkou matici jako je tato:

Vyjádření matice prostřednictvím seznamu obsahuje množství nul:

matrix = [ [0,0,0,1,0],
           [0,0,0,0,0],
           [0,2,0,0,0],
           [0,0,0,0,0],
           [0,0,0,3,0] ]

Alternativou je použití slovníku. Jako klíče můžeme použít entice, obsahující čísla řádků a sloupců. Zde je slovníkové vyjádření téže matice:

>>> matrix = {(0,3): 1, (2,1): 2, (4,3): 3}

Potřebujeme jenom tři dvojice klíč-hodnota pro tři nenulové prvky matice. Každý klíč je entice a každá hodnota je celé číslo.

Prvky matice jsou přístupné pomocí operátoru [ ]:

>>> matrix[0,3]
1

Všimněme si, že vyjádření matice slovníkem má jinou skladbu než vyjádření matice vnořenými seznamy. Místo dvou celočíselných indexů používáme jenom jeden, jímž je entice z celých čísel.

Je zde však jeden problém. Pokusíme-li se ukázat na nulový prvek matice, dostaneme chybu, protože ve slovníku takový klíč uvedený nemáme:

>>> matrix[1,3]
keyerror: (1, 3)

Tento problém řeší metoda get:

>>> matrix.get((0,3), 0)
1

Prvním argumentem je klíč, druhým argumentem je hodnota, kterou má funkce get vrátit, nebude-li zadávaný klíč ve slovníku:

>>> matrix.get((1,3), 0)
0

Metoda get rozhodně zlepšuje přístup k prvkům řídké matice.


11.5 Počítání písmen

V odstavci 7.11 jsme napsali funkci, která počítala četnost písmene v řetězci. Obecnější formou tohoto problému je vytvoření histogramu písmen v řetězci, to jest, kolikrát se které písmeno vyskytne.

Takový histogram by mohl být užitečný pro komprimaci textového souboru. Protože se různá čísla vyskytují s různou četností, můžeme soubor komprimovat s použitím kratších kódů pro často se vyskytující písmena a delších kódů pro písmena s menší četností.

Pomocí slovníku vytvoříme histogram elegantním způsobem:

>>> letter_counts = {}
>>> for letter in "Mississippi":
...     letter_counts[letter] = letter_counts.get (letter, 0) + 1
...
>>> letter_counts
{'M': 1, 's': 4, 'p': 2, 'i': 4}

Začínáme prázdným slovníkem. Pro každé písmeno v řetězci zvětšíme aktuální četnost (může být i nula) o 1. Na konci procesu máme slovník obsahující dvojice z písmen a jejich četností.

Bylo by ještě působivější, kdybychom histogram uspořádali podle abecedy. Můžeme to udělat pomocí univerzální funkce sorted(). Tuto funkci lze použít pro seznamy, řetězce, entice, sety i slovníky:

>>> sorted(letter_counts)
[('M', 1), ('i', 4), ('p', 2), ('s', 4)]

Proč je M před i? Vzpomeňte si na funkci ord():

>>> ord("M"), ord("i")
(77, 105)

11.6 Glosář

slovník (dictionary)
Kolekce dvojic klíč-hodnota, kde klíče ukazují na hodnotu (mapují hodnotu). Klíčem může být jakýkoliv neměnitelný typ, hodnoty mohou být libovolného typu.
dvojice klíč-hodnota (key-value pair)
Párová položka ve slovníku.
invokace (invocation)
Volání metody.
náznak (hint)
Spočítaná a dočasně uložená hodnota, nahrazující zbytečně opakovaný výpočet.
přetečení (overflow)
Číselný výsledek příliš veliký na to, aby mohl být reprezentován číselným formátem.

11.7 Cvičení

  1. Napište program, který přečte řetězec a vrátí tabulku s abecedně uspořádanými písmeny včetně jejich výskytů. Velká písmena se od malých nerozlišují. Výstup programu by mohl vypadat například takto:

    a  2
    c  1
    d  1
    e  5
    g  1
    h  2
    i  4
    l  2
    n  2
    o  1
    p  2
    r  4
    s  5
    t  5
    u  1
    w  2
    
  2. Uveďte odezvu IPP v sedmi následujících případech v jedné souvislé seanci:
    1. >>> d = {"apples":15, "bananas":35, "grapes":12}
      >>> d["bananas"]
      
    2. >>> d["oranges"] = 20
      >>> len(d)
      
    3. >>> "grapes" in d
      
    4. >>> d["pears"]
      
    5. >>> d.get("pears", 0)
      
    6. >>> fruits = d.keys()
      >>> sorted(fruits)
      
    7. >>> del d["apples"]
      >>> "apples" in d
      

    Snažte se každému výrazu řádně porozumět. Pochopené uplatníte při doplnění těla následující funkce:

    def add_fruit(inventory, fruit, quantity=0):
        pass
    
    # tyto testy by měly vyjít
    new_inventory = {}
    add_fruit(new_inventory, 'strawberries', 10)
    test('strawberries' in new_inventory, True)
    test(new_inventory['strawberries'], 10)
    add_fruit(new_inventory, 'strawberries', 25)
    test(new_inventory['strawberries'] , 35)
    
    

previous up next hi end end