|
| 1 | +# Iterátory n-tic |
| 2 | + |
| 3 | +Některé hodnoty v Pythonu jsou *iterovatelné* (angl. *iterable*): |
| 4 | +obsahují sekvenci jiných hodnot a lze je „projít“ (iterovat) cyklem `for` nebo |
| 5 | +je převést na seznam. |
| 6 | +Už jich známe několik: |
| 7 | + |
| 8 | +```pycon |
| 9 | +>>> list(range(10)) # sekvence čísel |
| 10 | +>>> list('ahoj') # řetězec |
| 11 | +>>> list(['Ahoj', 'Hello', 'Hei']) # seznam |
| 12 | +>>> list((12, 'Sr', True)) # n-tice |
| 13 | +``` |
| 14 | + |
| 15 | +Spousta těchto typů umí něco navíc: zjistit jestli obsahují nějaký prvek |
| 16 | +(`4 in range(10)`), zjistit délku (`len([1, 2, 3])`), převést na velká písmena |
| 17 | +(`'abc'.upper()`). |
| 18 | +Nic z toho ale není potřeba, aby byl objekt iterovatelný. |
| 19 | + |
| 20 | +Podívejme se na dva dalších iterovatelné objekty: `enumerate` a `zip`. |
| 21 | + |
| 22 | + |
| 23 | +## Enumerate: očíslování sekvence |
| 24 | + |
| 25 | +Funkce `enumerate` vezme nějakou existující sekvenci a *očísluje ji*: |
| 26 | +ve vrácené sekvenci budou dvojice (index, původní hodnota). |
| 27 | + |
| 28 | +Řekněme že máš tento seznam: |
| 29 | + |
| 30 | +```python |
| 31 | +trpaslici = ['Prófa', 'Stydlín', 'Dřímal', 'Kejchal', 'Štístko', |
| 32 | + 'Šmudla', 'Rejpal'] |
| 33 | +``` |
| 34 | + |
| 35 | +Když na něj použiješ `enumerate`, dostaneš objekt `enumerate`, |
| 36 | +který podobně jako `range()` neukáže svůj obsah „rovnou“, |
| 37 | +ale můžeš se „do něj“ podívat převedením na seznam. |
| 38 | +Uvidíš tak seznam dvojic (číslo, trpaslík): |
| 39 | + |
| 40 | +```pycon |
| 41 | +>>> enumerate(trpaslici) |
| 42 | +<enumerate object at 0x7f0db61b29d8> |
| 43 | +>>> list(enumerate(trpaslici)) |
| 44 | +[(0, 'Prófa'), (1, 'Stydlín'), (2, 'Dřímal'), (3, 'Kejchal'), (4, 'Štístko'), (5, 'Šmudla'), (6, 'Rejpal')] |
| 45 | +``` |
| 46 | + |
| 47 | +Místo převedení na seznam můžeš přes objekt `enumerate` iterovat cyklem `for` |
| 48 | +a pro každou dvojici něco udělat. |
| 49 | +Třeba ji hezky vypsat: |
| 50 | + |
| 51 | +```python |
| 52 | +for dvojice in enumerate(trpaslici): |
| 53 | + # Rozbalení dvojice |
| 54 | + index, trpaslik = dvojice |
| 55 | + # Vypsání |
| 56 | + print(f'Na pozici {index} je {trpaslik}!') |
| 57 | +``` |
| 58 | + |
| 59 | +Objekt, který funkce `enumerate` vrací, je *iterátor dvojic* – sekvence, |
| 60 | +jejíž prvky jsou dvojice. |
| 61 | + |
| 62 | +## Rozbalování v cyklu for |
| 63 | + |
| 64 | +„Trpasličí“ cyklus se dá rozepsat takto: |
| 65 | + |
| 66 | +```python |
| 67 | +dvojice = 0, 'Prófa' # toto dělá `for` |
| 68 | +index, trpaslik = dvojice |
| 69 | +print(f'Na pozici {index} je {trpaslik}!') |
| 70 | + |
| 71 | +dvojice = 1, 'Stydlín' # toto dělá `for` |
| 72 | +index, trpaslik = dvojice |
| 73 | +print(f'Na pozici {index} je {trpaslik}!') |
| 74 | + |
| 75 | +dvojice = 2, 'Dřímal' # toto dělá `for` |
| 76 | +index, trpaslik = dvojice |
| 77 | +print(f'Na pozici {index} je {trpaslik}!') |
| 78 | + |
| 79 | +# A tak dále |
| 80 | +``` |
| 81 | + |
| 82 | +Kdybys to psal{{a}} ručně, lze to zjednodušit – přiřadit do dvou proměnných |
| 83 | +najedno, bez pomocné `dvojice`: |
| 84 | + |
| 85 | +```python |
| 86 | +index, trpaslik = 0, 'Prófa' # toto by mohl dělat `for` |
| 87 | +print(f'Na pozici {index} je {trpaslik}!') |
| 88 | + |
| 89 | +index, trpaslik = 1, 'Stydlín' # toto by mohl dělat `for` |
| 90 | +print(f'Na pozici {index} je {trpaslik}!') |
| 91 | + |
| 92 | +index, trpaslik = 2, 'Dřímal' # toto by mohl dělat `for` |
| 93 | +print(f'Na pozici {index} je {trpaslik}!') |
| 94 | + |
| 95 | +# A tak dále |
| 96 | +``` |
| 97 | + |
| 98 | +A `for` tohle ve skutečnosti umí: místo do proměnné `dvojice` může přiřadit |
| 99 | +rovnou do dvou proměnných `index, trpaslik`: |
| 100 | + |
| 101 | +```python |
| 102 | +for index, trpaslik in enumerate(trpaslici): |
| 103 | + print(f'Na pozici {index} je {trpaslik}!') |
| 104 | +``` |
| 105 | + |
| 106 | +Tohle je docela častẙ způsob práce s *iterátorem n-tic* – máš-li sekvenci, |
| 107 | +jejíž prvky jsou <var>n</var>-tice, můžeš jednotlivé součásti <var>n</var>-tice |
| 108 | +rozbalit přímo v hlavičce `for` cyklu. |
| 109 | + |
| 110 | +Zkus si to! Zkopíruj si tento seznam: |
| 111 | + |
| 112 | +```python |
| 113 | +dny = ['Po', 'Út', 'St', 'Čt', 'Pá', 'So', 'Ne'] |
| 114 | +``` |
| 115 | + |
| 116 | +… a zkus vypsat: |
| 117 | + |
| 118 | +```plain |
| 119 | +1. Po |
| 120 | +2. Út |
| 121 | +3. St |
| 122 | +4. Čt |
| 123 | +5. Pá |
| 124 | +6. So |
| 125 | +7. Ne |
| 126 | +``` |
| 127 | + |
| 128 | +{% filter solution %} |
| 129 | + |
| 130 | +```python |
| 131 | +dny = ['Po', 'Út', 'St', 'Čt', 'Pá', 'So', 'Ne'] |
| 132 | +for index, den in enumerate(dny): |
| 133 | + cislo = index + 1 |
| 134 | + print(f'{cislo}. {den}') |
| 135 | +``` |
| 136 | + |
| 137 | +To je trošku kostrbaté, ale dá se to zjednodušit: funkce `enumerate` zná |
| 138 | +pojmenovaný argument `start`, pomocí kterého umí sama |
| 139 | +počítat od jiného začátku než od nuly: |
| 140 | + |
| 141 | +```python |
| 142 | +dny = ['Po', 'Út', 'St', 'Čt', 'Pá', 'So', 'Ne'] |
| 143 | +for index, den in enumerate(dny, start=1): |
| 144 | + print(f'{index}. {den}') |
| 145 | +``` |
| 146 | + |
| 147 | +{% endfilter %} |
| 148 | + |
| 149 | + |
| 150 | +## Zip: Víc iterací najednou |
| 151 | + |
| 152 | +Další iterátor <var>n</var>-tic je funkce `zip`, která umí projít dvě sekvence |
| 153 | +naráz. |
| 154 | +Řekněme že máš seznam věcí a k nim příslušných barev: |
| 155 | + |
| 156 | +``` python |
| 157 | +veci = ['tráva', 'slunce', 'mrkev', 'řeka'] |
| 158 | +barvy = ['zelená', 'žluté', 'oranžová', 'modrá'] |
| 159 | +``` |
| 160 | + |
| 161 | +Kdtyž tyto dva seznamy dáš funkci `zip`, dostaneš iterátor který příslušné |
| 162 | +hodnoty spáruje. |
| 163 | +Bude tedy obsahovat: |
| 164 | + |
| 165 | +* Dvojici prvních prvků obou seznamů |
| 166 | +* Dvojici druhých prvků obou seznamů |
| 167 | +* Dvojici třetích prvků obou seznamů |
| 168 | +* ... |
| 169 | + |
| 170 | +``` python |
| 171 | +for vec, barva in zip(veci, barvy): |
| 172 | + print(f"{vec} je {barva}") |
| 173 | +``` |
| 174 | + |
| 175 | +Funguje to i pro více sekvencí. |
| 176 | +V následujícím případě je výsledný `zip` iterátor čtveřic (věc, barva, |
| 177 | +místo, číslo): |
| 178 | + |
| 179 | +``` python |
| 180 | +veci = ['tráva', 'slunce', 'mrkev', 'řeka'] |
| 181 | +barvy = ['zelená', 'žluté', 'oranžová', 'modrá'] |
| 182 | +mista = ['na zemi', 'nahoře', 'na talíři', 'za zídkou'] |
| 183 | +cisla = range(4) |
| 184 | + |
| 185 | +for vec, barva, misto, cislo in zip(veci, barvy, mista, cisla): |
| 186 | + print(f"{cislo}. {barva} {vec} je {misto}") |
| 187 | +``` |
| 188 | + |
| 189 | +Když si ale vypíšeš samotný objekt `zip`, zjistíš že o sobě nic moc neřekne |
| 190 | +– podobně jako `enumerate`: |
| 191 | + |
| 192 | +```pycon |
| 193 | +>>> zip(veci, barvy, mista, cisla) |
| 194 | +<zip object at 0x7f0db61b1f48> |
| 195 | +``` |
0 commit comments