Cyklus for

Zapisuje se jako for název_proměnné in sekvence: a danou sekvenci prochází prvek po prvku. Podívejme se na pár ukázek.

>>> for z in "pepa": ... print(z) ... p e p a >>> for x in (0, 2, 3, 7): ... print(x) ... 0 2 3 7 >>> for i in range(4): ... print(i) ... 0 1 2 3

Jak je vidět, sekvencí může být hodně různých věcí – jinak se ale cyklus for chová docela přirozeně. Nenechte se zmást slovem in – z hlediska jazyka Python má to slovo tentokrát úplně jiný význam, než když jej použijeme v podmínce.

Funkce range

Jednou z podivnějších (ale v běžném používání nejčastějších) možností, na co zavolat cyklus, je funkce range(počet). Způsobí, že cyklus vykoná počet kroků, a projde tak čísla od 0 do (počet − 1). K samotnému číslu, jaké jsme zadali, se tedy nedostane.

Příklad. Přepište následující kód pomocí cyklu for a s využitím range.

i = 0 while i < 10: print("Číslo: " + str(i)) i += 1 Řešení. for i in range(10): print("Číslo: " + str(i))

Všimněte si jednoho podstatného rozdílu: cyklus for se nenechá nijak rozhodit, když měníme proměnnou, která sekvenci prochází (v našem případě i). V příštím kroku cyklu se do ní vždy nastaví další prvek sekvence. Pro ilustraci se podívejme na dva kusy kódu, které jsou napohled podobné:

>>> for i in range(3): ... i += 2 ... print(i) ... 2 3 4 >>> i = 0 >>> while i < 3: ... i += 2 ... print(i) ... 2 4

Chceme-li, jako v první z předchozích ukázek, projít čísla od dvou do čtyř, můžeme použít delšího volání range(odkud, kam, [krok]). Začne se číslem odkud, ale podobně jako v tom jednodušším případě se zastavíme už před číslem kam.

>>> for i in range(3, 7): ... print(i) ... 3 4 5 6

Navíc můžeme přidat nenulové číslo krok, tj. hodnotu, o kterou sekvence v každém kroku roste. Když dáme záporné číslo a správné hranice odkud, kam, můžeme projít čísla pozpátku:

>>> for i in range(6, 0, -2): ... print(i) ... 6 4 2

Příklad. Vypište všechny násobky 17, které jsou větší než 1000000 a menší než 1000100. Rada: 1000008 je dělitelné 17.

Řešení. for x in range(1000008, 1000100, 17): print(x)

Funkce count

Pro vyzkoušení všech nezáporných čísel se range použít nedá, protože nemáme žádnou horní hranici. Elegantní řešení nabízí funkce count z modulu itertools. Než ji budeme moct použít, musíme tedy zavolat import.

>>> from itertools import count >>> for i in count(): ... print(i) ... 0 1 2 A tak dál... nekonečný cyklus můžete i v tomto případě zastavit zkratkou Ctrl+C

Kreativní vložka: hledání hrubou silou

Některé úlohy (ale zdaleka ne všechny) jde v počítači řešit hrubou silou, to znamená zkoušením všech možností. Když jsou možnostmi přirozená čísla, poslouží nám perfektně funkce count. Když potřebujeme ale například dvojice čísel, nestačí dát dva takové cykly do sebe: ten vnitřní poběží do nekonečna a ten vnější by se tedy nikdy nedostal z čísla 0. Musíme se tomu nějak vyhnout a zařídit, aby jeden z cyklů byl konečný.

V některých případech si můžeme pomoct tak, že budeme zkoušet jenom dvojice (větší_číslo, menší_číslo). Nekonečným cyklem pak určíme to větší z nich a vnořeným, konečným cyklem vyzkoušíme všechna čísla od 0 do větší_číslo.

for vetsi in count(): for mensi in range(vetsi+1):

Příklad. Napište program, který postupně vypíše všechny pythagorejské trojice (a2 + b2 = c2).

Řešení. from itertools import count for a in count(1): # cyklus od 1 do nekonečna for b in range(1, a): # cyklus od 1 do a-1 ctverec = a**2 + b**2 c = int(ctverec**0.5) if c**2 == ctverec: print(a, b, c)

Dá se docela elegantně zvládnout i případ, kdy bychom chtěli zkoušet opravdu všechny dvojice. Zkuste si rozmyslet jak, není to nic těžkého.

Odmocňování může způsobovat potíže, protože se počítá ve floating-point aritmetice a má proto omezenou přesnost. Pro čísla pochopitelná lidským rozumem to nemá moc vliv, ale když si zkusíme vyrobit nějaké hodně velké číslo (a ujistíme se přitom, že jeho odmocnina je celočíselná), odmocňováním nám může vyjít špatný výsledek a po jeho umocnění tedy vyjde jiné číslo.

>>> a = 26465262305967553 ** 2 >>> a 700410108923667000903915488807809 >>> int(a**0.5)**2 700410108923666947973390876872704

Kreativní vložka: hledání půlením

Následující postup vyhledávání najde spoustu různých uplatnění a dlužno poznamenat, že ho použijeme poměrně zvráceným způsobem. Zkusíme s jeho pomocí rychle počítat odmocninu, pokud vychází celočíselná. Nejdříve zde popíšeme celý algoritmus obecně, pak ho přiohneme na tohle zadání.

Hledání půlením – algoritmus

Východiskem je nějaká sekvence (v našem případě úsek přirozených čísel) a nějaká podmínka pro její hodnoty. Chceme napsat program, který najde první hodnotu v sekvenci, která podmínku splňuje. Co je důležité, máme předem zaručené, že pro všechny hodnoty za touto první už podmínka bude platit. Nejčastěji je to tak, že hodnoty v sekvenci jsou seřazené od nejmenších po největší (jako v našem případě) a hledáme první hodnotu, která je větší než nějaké zadané x. Můžeme se tedy opřít o to, že všechny hodnoty za tou hledanou budou také určitě větší než x.

Na začátku máme danou nějakou dolní mez (v našem případě 0) a horní mez (v našem případě x, protože odmocnina z takhle velkého čísla bude vždycky menší než číslo samotné). Podíváme se do poloviny mezi nimi (tu případně vhodným způsobem zaokrouhlíme) a hodnotu v tom místě si pro teď označíme třeba i. Pokud podmínka pro i platí, bude hledaná hodnota jistě někde vlevo od i, takže můžeme do i posunout horní mez vyhledávání a postup zopakovat. Obdobně, když podmínka neplatí, hledaná hodnota bude někde vpravo, takže posuneme dolní mez a zopakujeme postup. Skončíme až v okamžiku, kdy nám horní a dolní mez jasně určují jedinou hodnotu.

Předchozí odstavec se záměrně vyhýbá podrobnostem ve výpočtech, na kterých ale hodně záleží. Stanovíme si, že pro hodnotu na dolní mezi podmínka nikdy neplatí a pro hodnotu na horní mezi vždycky platí – hledaná hodnota tedy bude ležet vpravo od dolní meze, ale může být přímo na té horní. Místo volání nějaké funkce rekurzí (aby funkce volala sebe samotnou) bude rychlejší a přehlednější použít while cyklus. Cyklus má skončit ve chvíli, kdy dolní a horní mez jsou dvě sousední hodnoty: výsledkem je hodnota na horní mezi.

Protože jsme se od začátku chtěli vyhnout necelým číslům, musíme se bez nich obejít i při počítání poloviny. To samozřejmě jde: stačí dělení se zbytkem, jak ho známe ze třetí třídy (ale zbytek po dělení nás tentokrát nezajímá). V Pythonu se zapisuje dvojitým lomítkem, například 5 // 2 == 2, zaokrouhluje se dolů. Potřebný výpočet je potom obyčejný aritmetický průměr: i = (dolni_mez + horni_mez) // 2. Na zaokrouhlování musíme pomyslet a ujistit se, že takhle spočítaný průměr mezi dolní a horní mezí se nemůže rovnat ani jedné z nich. Máme štěstí, nemůže: stalo by se to leda v případě, že budou obě meze na dvou sousedních hodnotách, ale v tu chvíli už cyklus skončí.

Použití

V případě hledání odmocniny bude pro zadané y podmínkou y**2 >= x. Pokud odmocnina z x je celé číslo, mělo by se vyhledávání zastavit přímo na hodnotě y**2 == x, jinak najde něco o chlup většího.

Příklad. Napište funkci odm(x), která zkusí najít odmocninu z x a navrátí False v případě, že to není celé číslo. Na řešení se prosím podívejte teprve potom, co napíšete svůj vlastní program.

Řešení. def odm(x): low = 0 high = x while low + 1 < high: i = (low + high) // 2 if i**2 >= x: high = i else: low = i if high**2 == x: return high else: return False

Podmínkové výrazy

Někdy se smí celá podmínka zapsat na jeden řádek. Konkrétně to jde tehdy, když všechny větve podmínky přímo navracejí nějakou hodnotu (jako v předchozím řešení) nebo nastavují nějakou hodnotu všechny do té samé proměnné. Následující kód:

if x > y: vetsi = x else: vetsi = y

...můžeme zestručnit jako:

vetsi = x if (x > y) else y

(Ale nejlepší řešení by bylo použít zabudovanou funkci max(x, y).) Závorku kolem podmínky můžeme vynechat, ale většinou prospívá čitelnosti. Pamatujte si ještě, že podobný výběr proměnných jde použít jenom na pravé straně rovnítka – pro výpočet hodnoty, ale nejde tak určit proměnnou, do které se má dosazovat. Nejde tímhle způsobem zavolat return v některých případech a jindy nechat funkci běžet – můžeme si akorát vybrat, jaká hodnota se navrátí. Následující kód je tedy potřeba rozepsat obyčejnou podmínkou.

>>> (x if (x > y) else y) = "Tahle proměnná byla větší" File "<stdin>", line 1 SyntaxError: can't assign to conditional expression

Příklad. Přepište předchozí kód funkce odm s využitím podmínkového výrazu.

Řešení. def odm(x): low = 0 high = x while low + 1 < high: i = (low + high) // 2 if i**2 >= x: high = i else: low = i return high if high**2 == x else False