====== 4. Složené datové typy ====== Přehled datových typů dostupných v základní instalaci Pythonu Základní: * ''%%int%%'': Celé číslo (integer) * ''%%float%%'': Desetinné číslo * ''%%str%%'': Textový řetězec (string) * ''%%bool%%'': Binární logická hodnota * ''%%complex%%'': Komplexní číslo * ''%%bytes%%'': Binární hodnota (nereprezentovaná) Složené: * ''%%list%%'': Seznam * ''%%tuple%%'': N-tice * ''%%range%%'': Rovnoměrná posloupnost * ''%%set%%'', ''%%frozenset%%'': Množina * ''%%str%%'': Textový retězec (string) * ''%%dict%%'': Slovník * ''%%bytearray%%'': Pole binárních hodnot * ''%%memoryview%%'': Binární obraz ===== Seznam: list ===== Seznam je kolekce hodnot stejných nebo různých datových typů. Pro výčet metod seznamů zadejte ''%%dir(list)%%'' * ''%%x = [1, 2, 3, 4]%%'', je seznam tvořený čtveřicí čísel typu ''%%int%%'' jejichž hodnoty jsou ''%%1%%'', ''%%2%%'', ''%%3%%'' a ''%%4%%'' * ''%%y = [1, '2', 3, 4]%%'', je seznam tvořený trojicí čísel typu ''%%int%%'' jejichž hodnoty jsou ''%%1%%'', ''%%3%%'' a ''%%4%%'' a znakem ''%%'2'%%'' K jednotlivým prvkům (elementům) seznamu můžeme přistupovat pomocí indexu, čísla typu ''%%int%%'', v hranatých závorkách * ''%%x[0]%%'' nebo ''%%y[0]%%'' vrátí první prvek v seznamu, v obou případech se jedná o číslo ''%%1%%'' -- v Pythonu se indexuje od 0 * ''%%x[3]%%'' nebo ''%%y[3]%%'' vrátí poslední prvek v seznamu, v obou případech se jedná o číslo ''%%4%%'' -- poslední prvek seznamu má index o jedna menší než je délka seznamu (počtu prvků seznamu), kterou můžeme získat funkcí ''%%len()%%'' * ''%%x[3] == x[len(x)-1]%%'' a ''%%y[3] == y[len(y)-1]%%'' * přístup k poslednímu prvku seznamu se v Pythonu může provést elegantně pomocí indexu ''%%-1%%'': ''%%x[3] == x[-1]%%'' a ''%%y[3] == y[-1]%%'' Pomocí indexů mohu také měnit hodnoty jednotlivých prvků v seznamu * ''%%y[0] = 5%%'' změní první prvek seznamu ''%%y%%'' na ''%%5%%'' Ze seznamů můžeme také vybírat menší podseznamy pomocí řezů * ''%%x[0:3] == x[:3] == [1,2,3]%%'' což znamená, že řez je proveden od ''%%x[0]%%'' až do ''%%x[3-1]%%'' Při vytváření řezů, můžeme zadat také krok, s jakým se seznam bude procházet * ''%%x[1:4:2] = [2,4]%%'' nebo ''%%x[::2] = [1,3]%%'' projde celý seznam s krokem 2 * pokud zadáme záporný krok, seznam bude procházen pospátku: ''%%x[::-2] = [4,2]%%'' # bunka pro hrani se seznamy Jelikož jsou indexy seznamu celá čísla a seznamy mohou obecně nabývat spousty hodnot, je vhodné se seznamy pracovat pomocí cyklů seznam = [1, 3, 6] # vytvorime 1D seznam for i in seznam: # k jednotlivycm prvkum seznamu muzeme pristupovat napriklad ve for cyklu print(i, end=' ') print() # nebo pomoci indexu, kdy nechame for cyklus opakovat tolikrat, kolik prvku mame v seznamu: len(seznam) for i in range(len(seznam)): print(seznam[i],end=' ') # pro zajímavost - výstupem funkce enumerate je index prvu v seznamu i samotný prvek print() for i, prvek in enumerate(seznam): print(prvek,end=' ') print(seznam[i],end=' ') ==== Vytvoření seznamu ==== * seznam můžeme vytvářet buď přímo výčtem hodnot oddělených čárkou v hranatých závorkách: ''%%x = [1,2,3,4]%%'', někdy je vhodné takto vytvořit i prázdný seznam ''%%y = []%%'' (inicializovat si proměnnou) * přidávat hodnoty do existujícího seznamu (buď prázdného nebo ne) pak můžeme pomocí metody ''%%append()%%'': ''%%y.append(hodnota)%%'' * v Pythonu je k dispozici tzv. seznamová komprehenze, která vytvoří seznam na jednom řádku, např. ''%%z = [i for i in range(10)]%%'' y = [] # prazdny seznam for i in range(10): y.append(i) print(y) # append je metoda datoveho typu seznam, podivejte se na dalsi metody aplikovatelne na seznam, umoznuji napriklad vyjimani prvku, razeni seznamu atd. z = [i for i in range(10)] # stejny vysledek pomoci seznamove komprehenze print(z) ==== Úloha 1. Fibonacciho posloupnost ==== Vytvořte seznam jehož prvky bude [[https://en.wikipedia.org/wiki/Fibonacci_number|Fibonacciho]] posloupnost o ''%%n%%'' prvcích. Postup ve zkratce: $$F_0=0, F_1=1, F_n=F_{n-1}+F_{n-2}$$ n = 20 # pocet prvku rady # zde piste svuj kod ==== Úloha 2. Součet kladných čísel ==== Napište funkci jejímž argumentem je seznam celých čísel a která vrátí součet pozitvních čísel z daného seznamu. seznam = [95, 23, -3, 42, 50, -39, 48, -43, 7, -31, -85, 38, 25, -38, 1, -14, 79, -55, -34, -87] #408 # zde piste svuj kod ==== Úloha 3. Přátelé Foa ==== Napište funkci, která vyfiltruje seznam řetězců obsahující jména. Vyberte ta jména, která mají přesně čtyři znaky, to jsou přátelé Foa. Tato jména budou vrácena funkcí jako seznam řetězců. Ex: vstup = ["Ryan", "Kieran", "Jason", "Yous"], Výstup = ["Ryan", "Yous"] jmena = ["Ryan", "Kieran", "Jason", "Yous"] # zde piste kod ==== Úloha 4. Eratostheneovo síto pro nalezení prvočísel ==== Napište funkci, která vrátí seznam tvořený prvočísly od prvního prvočísla až do čísla ''%%n%%'', které bude argumentem funkce. Pro nalezení prvočísel využijte algoritmus zvaný [[https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes|Eratostheneovo síto]]. def Sieve_of_Eratosthenes(n): list_int = [x for x in range(2,n+1)] # make a list of integers from 2 to n list_mark = [True for x in range(2,n+1)] # make a list of True values of the same size as above # zde piste svuj kod ===== Seznam seznamů ===== Již bylo řečeno, že prvkem seznamu může být hodnota jakéhokoli datového typu, například seznam řetězců ''%%seznam_text = ['petr','pavel','josef']%%'' Je tedy možné vytvořit také seznam, jehož prvky budou seznamy ''%%matice = [[1,2,3],[4,5,6],[7,8,9]]%%'' * ''%%matice[0][0]%%'' představuje první prvek prvního prvku seznamu, tedy první prvek v prvním řádku matice * výše je uveden příklad matice, ale obecně může být každý seznam v seznamu různé délky Seznam je měnitelný datový typ, což v Pythonu znamená, že vytvoříme-li jeden seznam ''%%x = [1,2,3]%%'' a poté druhý seznam takto ''%%y = x%%'', jakákoli manipulace se seznamem ''%%y%%'' mění také seznam ''%%x%%'' Např. ''%%y[0] = 5%%'' Pokud tomu chceme předejít, musíme u 1D seznamů použít například klíčové slovo ''%%list%%'': ''%%y = list(x)%%'' V případě, že elementy seznamu jsou další seznamy, je nejlepší pro tzv. hlubokou kopii použít funkci ''%%deepcopy%%'' z modulu ''%%copy%%'' x = [1,2,3] y = x y[0] = 5 print(f'x = {x}, y = {y}') y = list(x) y[0] = 10 print(f'x = {x}, y = {y}') y = x.copy() # v případě 1D listu y[0] = 10 print(f'x = {x}, y = {y}') import copy x = [[2,3],2] y = copy.deepcopy(x) y[0][0] = 1 print(f'x = {x}, y = {y}') y2 = list(x) # toto je pouze melka kopie (vnitrni seznamy jsou v y2 a x stejne objekty) y2[0][0] = 100 print(f'x = {x}, y2 = {y2}') y3 = x.copy() # pozor!, .copy() v tomto pripade vytvari pouze melkou kopii y3[0][0] = 10 print(f'x = {x}, y3 = {y3}') ==== Vytvoření matice ==== * matici můžeme vytvořit pomocí for cyklů nebo seznamové komprehenze matice = [] # nejprve nadeklarujeme praznou matici n_radku = 3 n_sloupcu = 3 for i in range(n_radku): radek = [] for k in range(n_sloupcu): radek.append(i*n_sloupcu+k+1) matice.append(radek) print(matice) # pomoci seznamove komprehenze matice_c = [[i*n_sloupcu + k + 1 for k in range(n_sloupcu)] for i in range(n_radku)] print(matice_c) ==== Úloha 6. Součet matic. ==== Vytvořte funkci, která dostane jako argument dvojici matic a sečte je mat1 = [[1,2,3],[0,0,0],[5,5,5]] mat2 = [[-1,-2,-3],[1,1,1],[-3,-3,-3]] def soucet_matic(mat1,mat2): # zde napiste svuj kod print(soucet_matic(mat1,mat2)) ===== n-tice: tuple ===== n-tice je neměnitelný seznam, který můžeme nadefinovat například výčtem pomocí kulatých závorek nebo příkazu ''%%tuple%%'' t = () # An empty tuple t = (0, 'one') t = ('a', ['b', 'c'], (1, 2, 3)) t = tuple(range(10)) n-tice jsou užitečné například pokud necheme, aby funkce změnila hodnoty argumentů, protože v případě předání seznamu se hodnoty změní def pricti1(z,hodnota): for i in range(len(z)): z[i] += hodnota return z def pricti2(z,hodnota): z = list(z) # jediny rozdil mezi funkcemi for i in range(len(z)): z[i] += hodnota return z # test funkce pricti1 - vsimni si vystupu x = (1,2,3,4) # vytvori n-tici y = [1,2,3,4] # vytvori seznam print(pricti1(y,1)) # pujde print('seznam y = ',y) print(pricti1(x,1)) # nepujde print('seznam x = ',x) # test funkce pricti2 - vsimni si vystupu x = (1,2,3,4) # vytvori n-tici y = [1,2,3,4] # vytvori seznam print(pricti2(y,1)) # pujde print('seznam y = ',y) print(pricti2(x,1)) # pujde print('seznam x = ',x) ===== Množina (set) ===== * Jako množina v matematice * Kolekce různých datových typů, která není uspořádaná -- nelze tedy indexovat * Každý prvek je unikátní * Je modifikovatelná s = set() # An empty set s = {1, 1, 2, 2, 3} # The same as {1, 2, 3} s = set(range(10)) # vyuziti mnoziny pro vyber unikatnich prvku v seznamu x = [1, 1, 2, 3, 4, 5] x_unique = list(set(x)) print(x_unique) ==== Úloha 7. Opakující se písmena ==== V AJ (a dalších jazicíh) existuje pojem [[https://en.wikipedia.org/wiki/Heterogram_(literature)|Heterogram]]. Tento pojem označuje slovo či větu, ve které se žádné z písmen neopakuje (tedy každé písmeno je zastoupeno pouze jednou). Napište funkci, která zjistí zda je slovo heterogramem. Vraťte True nebo False. Využijte metodu **.lower()** pro převod slova na malá písmena. def is_heterogram(slovo): # vas kod slova = ['roh', 'loupak', 'polotovar', 'struhadlo', 'Ovoce', 'zamenictvi', 'scvrnkl', 'nejnezpravdepodobnostnovavatelnejsimi', 'dvacetikoruny'] for slovo in slova: if is_heterogram(slovo): print('Slovo {0:s} je heterogram!'.format(slovo)) else: print('Slovo {0:s} není heterogram.'.format(slovo)) ===== Slovník: dictionary ===== * Každý prvek tvořený **klíčem** (//key//) a **hodnotou** (//value//) * Hodnoty jsou ekvivalentní seznamu, klíče slouží k indexaci d1 = {} # An empty dictionary d2 = dict() # An empty dictionary d3 = dict.fromkeys(['one', 'two', 'three']) # Empty with keys 'one', 'two', 'three' d4 = dict.fromkeys('abcde') # Empty with keys 'a', 'b', 'c', 'd', 'e' d5 = {'one': 1, 'two': [1, 2, 3]} # By a literal d6 = dict(zip('keys', [1, 2, 3, 4])) # {'k': 1, 'e': 2, 'y': 3, 's': 4} * Indexování: d = {'a': [1, 2, 3], 'b': ['a', 'b', 'c']} d['a'][0] d['b'] ... d = {'Daniel': {'vek': 23, 'vaha':65, 'sourozenci':['Jan', 'Adela']}, 'Jan': {'vek': 21, 'vaha':80, 'sourozenci':['Daniel, Adela']}, 'Pavla': {'vek':22, 'vaha':55, 'sourozenci':['Iveta']}} print(d.keys()) print(d['Daniel'].keys()) print(d['Daniel']['sourozenci']) d['Cecil'] = {'vek':78, 'vaha':76, 'sourozenci':['Vitezslav']} print(d) ==== Úloha 8. Třídění ==== Musíte roztřídit pytel plný věcí. Na každé věci je etiketa, na které je napsaný primární (a případně i sekundární) materiál, z kterého je daná věc vyrobená. Vaším úkolem je věci správně roztřídit podle materiálu (papir, sklo, organicky_material, plast). Vstupem funkce je seznam veci, výstupem je n-tice/matice. Příklad: veci = [ {"typ": "jablka", "material": "organicky_material"}, {"typ": "jogurt", "material": "organicky_material", "sekundarniMaterial": "plast"}, {"typ": "lahev vina", "material": "sklo", "sekundarniMaterial": "papir"}, {"typ": "krabice", "material": "papir"}, {"typ": "igelitovy sacek", "material": "plast"}, {"typ": "lahev piva", "material": "sklo", "sekundarniMaterial": "papir"} ] vystup = ( ["lahev vina", "krabice", "lahev piva"], #papir ["lahev vina", "lahev piva"], #sklo ["jablka", "jogurt"], #organicky_material ["jogurt", "igelitovy sacek"] #plast ) def trideni(veci): # vas kod ===== Příklady na procvičení ve zbytku cvičení nebo doma ===== ==== Úloha 9. Vrať prostřední znak - na procvičení indexace ==== Napište funkci, která jako argument dostane slovo a vrátí prostřední znak slova pokud je délka slova lichá nebo prostřední dvojici znaků pokud je délka slova sudá. Příklad: * roh => **o** * loupak => **up** * nejnezpravdepodobnostnovavatelnejsimi => **o** * zamenictvi => **ni** ==== Úloha 10. Kreditní karta - na procvičení indexace ==== Při nákupu na internetu chceš použít kreditní/debetní kartu. Při zadávání čísel si všimneš, že jsou vždy viditelné akorát poslední 4 číslice (kvůli bezpečnosti). Dokážeš napsat funkci, která tzv. zamaskuje všechny znaky, až na poslední čtyři? Vstupem funkce je celé číslo, které je potřeba zamaskovat, a maskovací znak. V případě, že má číslo 4 číslice (či méně), vrať číslo bez maskování. V případě, že není zadán znak, použijte **#**. Příklad: * maskovani(90273874982936,'#') => '##########2936' * maskovani(123,'o') => 123 * maskovani(847563,'q') => 'qq7563' def maskovani(cislo, znak): # vas kod ==== Úloha 11. Procházka po městě - na procvičení práce s metodami, podmínkami (případně se slovníkem a množinami) ==== Pepíček žije ve měste, kde ulice vypadají jako [[https://en.wikipedia.org/wiki/Eixample|čtverečkový papír]] (stejně dlouhé a míří buď na sever, jih, východ nebo západ). Jeden den se Pepíček rozhodne, že půjde na výlet (Vyjádřeno seznamem, kde jednotlivá písmena značí orientaci. Vzdálenost je konstantní, tedy jedno písmeno = jedna jednotka vzdálenosti). Napište funkci, která určí zda se Pepíček dokázal vrátit domů nebo zda se na výletě ztratil. //Použijte metodu .count().// Příklad: * prochazka(['j', 'j', 'v', 'j', 'z', 's', 'z', 's', 's', 'z', 'v', 'v']) => True * prochazka(['j', 's', 'j', 'v', 'v']) => False def prochazka(cesta): # vas kod ==== Úloha 12. DNA - na procvičení práce se slovníkem, popřípadě seznamy ==== Deoxyribonucleic acid (DNA) nese "instrukce" pro rozvoj a funkci buněk živých organizmů. Pro více informací http://en.wikipedia.org/wiki/DNA V řetězci DNA, symboly "A" a "T" se navzájem doplňují stejně jako "C" a "G". Napište funkci, která dostane jako vstup jednu stranu DNA a doplní druhou stranu DNA. Více obdobných cvičení můžete najít [[http://rosalind.info/problems/list-view/|zde]] Příklad: (vstup --> výstup) ''%%"ATTGC" --> "TAACG"%%'' ''%%"GTAT" --> "CATA"%%'' def DNA_strand(dna): # Vas kod DNA_strand('ATTGC') ==== Úloha 13. Jsi nadpruměrný? - na procvičení práce s funkcemi a podmínkami (případně s cykly) ==== Prošel jsi testem a chtěl by jsi vědět, jestli byl Tvůj výsledek lepší než průměr ze všech bodů v Tvé třídě. Napiš funkci, která má jako argument seznam se všemi body ve třídě a druhý argument je Tvé bodové ohodnocení. Funkce spočítá průměr a porovná Tváj výsledek s průměrem. Pokud je větší, vrátí True, pokud ne vrátí False def better_than_average(body,tve_body): # zde vas kod test_arr = [12, 23, 34, 45, 56, 67, 78, 89, 90] better_than_average(test_arr, 69) ==== Úloha 14. Součin matice ==== Napiš funkci, která vypočítá součin matic podle pravidla o násobení matic ==== Úloha 15. Gaussova eliminace ==== Pokuste se implementovat Gaussovu eliminační metodu podle postupu v materiálech k předmětu [[https://cw.fel.cvut.cz/wiki/courses/b3b33alp/cviceni/t06|ALP]] (úkol 3). Řešení je možné nalézt ve [[https://www.youtube.com/watch?v=c9HKbcSB6Gk&feature=youtu.be|videu]] ==== Úloha 16. Continued fraction algorithm ==== Napište funkci, která provede tzv. [[https://en.wikipedia.org/wiki/Continued_fraction|continued fraction algorithm]], který rozloží racionální číslo větší než 1 do tvaru $$m_0 + \frac{1}{m_1+\frac{1}{m_2+\frac{1}{m_3 + ...}}}$$ Algoritmus je posán několika kroky: - začněte s ''%%n=0%%'' a číslem $ R$ které uložíme do seznamu ''%%x[n]%%'' - zaokrouhlení: ''%%m[n] = round(x[n])%%'' - zbytek: ''%%r[n] = x[n] - m[n]%%'' - pokud ''%%r[n] != 0%%'', pak ''%%x[n+1] = 1/r[n]%%'' a opakuj od bodu 2., jinak ukonči algoritmus - výstup je pak vektor ''%%m[n]%%'' a v případě nedokončeného algoritmu (například pokud ukončíme iteraci dříve nebo pokud číslo není možné zcela aproximovat) hodnota ''%%x[n+1]%%'' Při implementaci buď zvolte rozložitelné reálné číslo nebo pouze několik iterací, například pomocí for cyklu. Příklad pro $\pi = 3.14159$ a pouze jednu iteraci: * ''%%n=0%%'', ''%%x[0] = 3.14159%%'', ''%%m[0] = 3%%'', ''%%r[0] = 0.14%%'' * ''%%x[1] = 1/0.14159%%'', $\pi$ pak můžeme aproximovat jako $\pi \approx 3 + \frac{1}{7} = \frac{22}{7} $ ==== Úloha 17. Ověřte správnost continued fraction algoritmu z úlohy 3. ==== Napište funkci, která na svém vstupu bude mít seznam s koeficinety z CFA algoritmu a provede výpočet aproximovaného čísla Složitější varianta: Vyjádřete zadané racionální číslo jako zlomek