IB113 Radek Pelánek 2023 Rozcvička: šifra Pivot • společenský oděv nepřítele • trkací nástroje geografického útvaru • minerál cukruje • akustické projevy ustáleného chování o střední Morava bez oblečení • webová adresa okultní bytosti • části obličeje zeleninového pokrmu • alkoholický nápoj je aromatický • rozlehlost císařství • konzumuje severní sousedy Vstup: seznam českých slov, napr. https://wiki.korpus.cz/doku.php/seznamy: srovnavaci_seznamy (přes 300 tisíc slovních tvarů) Výstup: největší množina slov, které jsou vzájemnou přes myč kou vlasti, slavit, vstali, stavil, svitla, svalit vynikal, vanilky, vynikla, navykli, vnikaly, viklany kotle, loket, kotel, lokte, teklo, otekl (8 řádků kódu v Pythonu, výpočet pod 1 sekundu) Seznamy (pole) - motivace • razení studentů podle bodů na písemce • reprezentace herního plánu (piškvorky, šachy) 9 frekvence písmen v textu Frekvenční analýza nevhodně def frequency_analysis(text): text = text upper() freqA = 0 freqB = 0 freqC = 0 for letter in text: if letter == 'A': freqA += 1 elif letter == 'B': freqB += 1 elif letter == 'C : freqC += 1 print(1A1, freqA) print(1B1, freqB) print ( 'C , freqC) 0 12 3 4 • „více položek za sebou v pevném pořadí" • indexováno od nuly • základní koncept dostupný ve všech jazycích, běžně „pole" (array), položky stejného typu, pevně daná délka • seznamy v Pythonu - obecnější (ale pomalejší) • Python a pole - knihovna NumPy (nad rámec IB113) Seznamy v Pythonu 0 12 3 4 -5 -4 -3 -2 -1 • variabilní délka • položky mohou být různého typu • indexování i od konce (pomocí záporných Seznamy: použití v Pythonu s = [] # deklarace prázdného seznamu s = [3, 4, 1, 8] s [2] # indexace prvku, s [2] = 1 s[-l] # indexace od konce, s[-l] = 8 s [2] =15 # změna prvku s.append(6) # přidání prvku na konec s[l:4] # indexace intervalu, s[l:4J = C4> 15, 8] len(s) # délka seznamu, len(s) = 5 t = [3, "pes", [2, 7], -8.3] # seznam může obsahovat různé typy list ("pes") # přetypování na seznam anipulace se seznamy numbers = [3, 8, 7] numbers.append(10) numbers.insert(1, 11) numbers.remove(7) # přidání na konec seznamu # přidání na zadanou pozici # odstranění dané hodnoty Seznamy: konvence zápisu (PEP8) • mezera se dělá: za čárkou • mezera se nedělá: před čárkou, na „okrajích" 10/49 menovaní seznamu • nepoužívat: list (kolize s vestavěnou funkcí na pretypovaní) • neutrální názvy (primárně pro ukázky): alist, my_list • názvy dokumentující typ: num_list, str_list, numbers • názvy popisující význam: words, names, points, books Python: seznamy a cyklus for • cyklus for - přes prvky seznamu* • range - vrací seznam* čísel • typické použití: for i in range (n) • ale můžeme třeba: • for animal in ["dog", "cag", "pig"]: ... • for letter in "hello world": ... (*) ne úplně přesně - z důvodu efektivity se používají generátory a speciální „range object", v případě potřeby použijte explicitní pretypovaní na seznam: list (range (10)) < [S? ► < i ► < ± > i •o^o 12/49 Príklad: výpočet průměrné hodnoty def average1(num_list): total = 0 for i in range(len(num_list)): total += num_list[i] return total / len(num_list) def average2(num_list): total = 0 for value in num_list: total += value return total / len(num_list) def average3(num_list): return sum(num_list) / len(num_list) 13/49 Prvky a indexy jasně rozlišujte proměnné určené pro: indexy seznamu • typicky i, j • prvky seznamu • ideálně názvy odpovídající významu (name, height) • příp. generické value • rozhodně ne i, j 14/49 Vestavěná podpora pro práci se seznamy »> numbers = [4, 1, 8, 12, 3] >» sum (numbers) 28 >» min(numbers) 1 >» max (numbers) 12 >» 8 in numbers True 15/49 Ilustrace práce se seznamem def divisors_list(n): divisors = [] for i in ranged, n+1) : if n °/0 i == 0: divisors.append(i) return divisors divisors24 = divisors_list(24) print(divisors24) print(len(divisors24)) for x in divisors24: print(x**2) 16/49 Vytvorení seznamu různé způsoby vytvoření seznamu písmen abecedy: alphabet = list("abcdefghijklmnopqrstuvwxyz") alphabet = [] for i in range(26): alphabet.append(chr(ord(1 a')+i)) alphabet = [chr(ord(1 a')+i) for i in range(26)] Frekvenční analýza nevhodně def frequency_analysis(text): text = text upper() freqA = 0 freqB = 0 freqC = 0 for letter in text: if letter == 'A': freqA += 1 elif letter == 'B': freqB += 1 elif letter == 'C : freqC += 1 print(1A1, freqA) print(1B1, freqB) print ( 'C , freqC) Frekvenční analýza lépe def frequency_analysis(text): text = text upper() frequency = [0 for i in range(26)] for letter in text: if ord(letter) >= ord('A') and\ ord(letter) <= ord('Z'): frequency[ord(letter) - ord('A')] += for i in range(26): if frequency[i] != 0: print(chr(ord(1A1)+i), frequency [i]) Simulace volebního průzkumu - nevhodné řešen def survey(size, prefl, pref2, pref3): count1 = 0 count2 = 0 count3 = 0 for i in range(size): r = random.randint(1, 100) if r <= prefl: count1 += 1 elif r <= prefl + pref2: count2 += 1 elif r <= prefl + pref2 + pref3: count3 += 1 print ("Party 1:11, 100 * count 1 / size) print("Party 2:", 100 * count2 / size) print("Party 3:", 100 * count3 / size) 20/49 Simulace volebního průzkumu - lepší řešení def survey(size, pref): n = len(pref) count = [0 for i in range(n)] for _ in range(size): r = random.randint(1, 100) for i in range(n): if sum(pref [:i]) < r <= sum(pref [:i+1]) count [i] += 1 for i in range(n): print("Party", i+1, 100*count [i]/size) Toto řešení má stále nedostatky - zkuste dále vylepšit. 21 /49 • vstup: řetězec • výstup: zápis v Morseově abecedě • příklad: PES —. —. I . I . . . 22/49 Prevod do Morseovy abecedy nevhodně def to_morse(text): result = 11 for i in range(len(text)): if text[i] == 'A': result += 1 elif text[i] == 'B': result += elif text [i] == elif text[i] == # etc return result 'C 'D' result += result += i _ i _ 23/49 Prevod do Morseovy abecedy: využití seznamu morse = ['.-', '-..'] # etc def to_morse(text): result = 11 for i in range(len(text)): if ord('A') <= ord(text[i]) <= ord('Z'): c = ord(text [i]) - ord('A') result += morse [c] + 1 I1 return result (ještě lepší řešení: využití slovníku - bude později) Prevod z Morseovy abecedy def find_letter(sequence): for i in range(len(morse)): if morse[i] == sequence: return chr(ord('A') + i) return 1?1 def from_morse(message): result = 11 sequence = 11 for symbol in message: if symbol == 1|1: result += find_letter(sequence) sequence = 11 else: sequence += symbol return result < n ► vowels = Ma,e5 i,o,u,y" »> vowels, split(M,") ['a', 'e', 'i1, 'o1, 'u', 'y'] »> message = 11. -. . I---I -. . I . -" »> message. split (" I") 26/49 Príklad - načítání vstupu od uživatele »> input_string = inputO 3 7 »> xstring, ystring = input_string.split( »> x = int(xstring) »> y = int (ystring) Výškový prof i 475 rn n.m. Stoupáni: 367 m Klesaní: 363 m mapy.cz 28/49 heights_profile([3, 4, 5, 3, 4, 3, 2, 4, 5, 6, 5]) # # # # # # # # # # # # ###### #### ########### ########### Ascent 7 Descent 5 29/49 def heights_profile(heights): for v in range(max(heights)): for i in range(len(heights)): if heights [i] >= max(heights) - v: print ("#", end=M 11) else: print (" 5 end=M 11) print() print() •<□► 4 ^ t < -z ► 4 S ► 30/49 def elevation(heights): ascent = 0 descent = 0 for i in range(len(heights)-1): if heights [i] < heights [i+1]: ascent += heights[i+1] - heights [i] else: descent += heights [i] - heights [i+1] print ("Ascent11, ascent) print("Descent", descent) 31/49 Objekty, hodnoty, aliasy - stručné varování a = [1,2,3] 3 = 11,2,3] b = [1, 2, 3] nebo b = a[:] b = a [1,2,3] a—[1,2,3] b-M1,2,3] b • parametry funkcí - pouze volání hodnotou (na rozdíl např. od Pascalu: volání hodnotou a odkazem) • měnitelné objekty (např. seznam) však funkce může měnit • mělká vs hluboká kopie • více později 32/49 zualizace běhu programu http://www.pythontutor.com/ X = [1. y = [4, 3 z = y y = x x = z 6 7 x 31 SI [1 y = x x.append(4) y.append(5) z = [1. 2. 3 x.append(6) y.append(7) 14 y = "hello" 2 . 3] # a di fferent [1. 2. 3] List! 4. 5] # a different list! Frames Global variables x [_• 'L- Objects 0 1 2 4 5 6 st 0 1 2 1 2 3 vhodné např. pokud je nejasný některý z příkladů ve Zdvojnásobení seznamu Příklad: vstupem seznam čísel (např. [4, 1, 6]), chceme „získat dvojnásobky" (tj. 8, 2, 12) Důležité ujasnit, co přesně chceme: • vypsat dvojnásobky • vrátit nový seznam, který obsahuje dvojnásobky • změnit seznam, aby obsahoval dvojnásobky Jak vypadají jednotlivé programy? 34/49 • n-tice (tuples) • neměnitelná varianta seznamů • kulaté závorky místo hranatých (někdy lze vynechat): t = (1, 2, 3) • neměnitelné podobně jako řetězce • typické užití: • souřadnice: (x, y) • barva: (r, g, b) 9 použití pro přiřazení: a, b = b, a 35/49 Pascalův trojúhelník »> pascal_triangle(10) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 Explicitní vzorec (S) íl ín\ — n! (o) (i) ™ ~ (n-fe)!fc! Rekurzivní vztah (o) © © © © © © a) = (n1) + ("í1) 5 ^) c\ o 37/49 Pascalův trojúhelník def get_next_row(row): next_row = [1] for i in range(len(row)-1): next_row.append(row [i]+row [i+1]) next_row.append(1) return next_row def pascal_triangle(n): row = [1] for i in range(n): print(row) row = get_next_row(row) Kompaktní zápis pro zajímavost: def get_next_row(row): return [1] + [sum(p) for p in zip(row, row[1:])] + [1] 39/49 a dělitelné jen 1 a sebou samým • předmět zájmu matematiků od pradávna, cca od 70. důležité aplikace (moderní kryptologie) • problémy s prvočísly: • výpis (počet) prvočísel v intervalu • test prvočíselnosti • rozklad na prvočísla (hledání dělitelů) let i 40/49 Výpis prvočísel přímočaré def print.primes(how_many): n = 1 while how_many > 0: if len(divisors_list(n)) == 2: print (n, end=" 11) how_many -= 1 n += 1 print() 41/49 Eratosthenovo síto • problém: výpis prvočísel od 2 do n • algoritmus: opakovaně provádíme • označ další neškrtnuté číslo na seznamu jako prvočíslo • všechny násobky tohoto čísla vyškrtni 42/49 •<□► 4 ^ t < -Ž ► 4 S ► 43/49 def def thenovo sfto reset_multiples(is_candidate, i): k = i while k < len(is_candidate): is_candidate[k] = False k += i eratosthenes(n): is_candidate = [True for _ in range(n)] for i in range(2, n): if is_candidate [i]: print (i, end=M 11) reset_multiples(is_candidate, i) Pozn. Všimněte si, že funkce mění seznam. 44/49 Zajímavosti • prvočísla - Ulamova spirála • Pascalův trojúhelník - obarvení podle sudosti -Sierpiňského trojúhelník Vi Hart: Doodling in math: Sick number games https://www.youtube.com/watch?v=Yhlv5Aeuo_k 45/49 Úlohy se seznamem slov Vstup: seznam slov, např. ["kost", ■'rozum", "ale", "broskev", "igelit", "cesta", "elektrika"] • výpis prvních písmen • výpis délek slov • nejdelší slovo v seznamu • výpis slov obsahujících e • výpis písmen vyskytujících se za e 46/49 Kontrolní otázky • Je u datové struktury seznam důležité pořadí prvků? • Může v Pythonu seznam obsahovat položky různého typu? • Jakým příkazem přidáme do seznamu nový prvek? • Jak zjistíme délku seznamu? • Proč není dobrý nápad dát proměnné obsahující seznam jméno list? • Řetězec je v mnoha ohledech podobný jako „seznam znaku . V cem se lisí ( • Jak vytvořit seznam obsahující čísla od 1 do 5? (uveďte několik různých způsobů) • Jak zjistíme poslední prvek seznamu? Zkuste najít 3 různé způsoby 47/49 https://www.umimeinformatiku.cz/rozhodovacka https://www.umimeinformatiku.cz/porozumeni https://www.umimeinformatiku.cz/vystup-programu ^> sada „Seznamy" 48/49 • datová struktura seznam • základní operace se seznamy • příklady příště: algoritmy se seznamy - vyhledávání, řazení 49/49