C2184 Úvod do programování v PythonuC2184 Úvod do programování v Pythonu 5. Kolekce5. Kolekce KolekceKolekce Jsou objekty, které obsahují strukturovaně více hodnot. Mezi základní typy kolekcí patří: n-tice (tuple) – soubor n hodnot s daným pořadím, (1, 5, 1) seznam (list) – upravovatelný soubor hodnot s daným pořadím, [1, 5, 1] množina (set) – upravovatelný soubor unikátních hodnot bez pořadí, {1, 5} slovník (dict) – upravovatelný soubor pojmenovaných hodnot, {'x': 1, 'y': 5} Všechny kolekce jsou iterovatelné objekty. Seznam (Seznam (list)) Upravovatelný soubor hodnot s daným pořadím Vytváříme je: pomocí [] z jednotlivých prvků pomocí funkce list z jiného iterovatelného objektu Seznam lze modi kovat (narozdíl od řetězce): měnit, přidávat, odebírat prvky Používáme, když máme více obdobných objektů, např. seznam čísel, seznam studentů Nejčastěji používaný typ kolekce In [1]: In [2]: In [3]: In [4]: seznam = [1, 2, 3, 4, 5] seznam seznam = [] seznam pismena = list('hello') pismena cisla = list(range(5)) cisla Out[1]: [1, 2, 3, 4, 5] Out[2]: [] Out[3]: ['h', 'e', 'l', 'l', 'o'] Out[4]: [0, 1, 2, 3, 4] Některé funkce vrací seznam In [5]: 'Prasátko Peppa'.split() Out[5]: ['Prasátko', 'Peppa'] Na pořadí záleží In [6]: In [7]: [1, 2, 3] == [1, 2, 3] [1, 2, 3] == [1, 3, 2] Out[6]: True Out[7]: False IndexováníIndexování Jako u řetězců, počítáme zleva od 0, zprava od -1 In [8]: In [9]: In [10]: In [11]: seznam = [1, 2, 3, 4, 5] seznam[2] seznam[-1] seznam[1:4] seznam[:-2] Out[8]: 3 Out[9]: 5 Out[10]: [2, 3, 4] Out[11]: [1, 2, 3] Operace se seznamyOperace se seznamy Podobné jako u řetězců len – délka in, not in – přítomnost prvku count – počet výskytů prvku index – první výskyt prvku In [12]: In [13]: In [14]: In [15]: cisla = [1, 2, 5, 2] len(cisla) 5 in cisla cisla.count(2) cisla.index(2) Out[12]: 4 Out[13]: True Out[14]: 2 Out[15]: 1 Sřetězení In [16]: Opakování In [17]: [1, 2] + [5, 2, 8] [1, 2] * 3 Out[16]: [1, 2, 5, 2, 8] Out[17]: [1, 2, 1, 2, 1, 2] Matematické operace sum, min, max In [18]: In [19]: In [20]: (Tyto operace fungují na všech iterovatelných objektech, pokud to typově dává smysl.) In [21]: In [22]: cisla = [1, 2, 5, 2] sum(cisla) min(cisla) max(cisla) sum(range(5)) min('hello') # Minimum u řetězců = první v abecedě Out[18]: 10 Out[19]: 1 Out[20]: 5 Out[21]: 10 Out[22]: 'e' Logické funkce all (všechny prvky pravdivé) a any (aspoň jeden prvek pravdivý) In [23]: In [24]: all([True, True, True, False]) any([True, True, True, False]) Out[23]: False Out[24]: True Modi kace seznamůModi kace seznamů In [25]: In [26]: In [27]: seznam seznam[2] = 8 seznam Out[25]: [1, 2, 3, 4, 5] Out[27]: [1, 2, 8, 4, 5] Přidávání prvkůPřidávání prvků Metoda append(prvek) přidá nový prvek na konec Metoda insert(index, prvek) přidá prvek na daný index (následující prvky se posouvají o 1 doprava) In [28]: In [29]: In [30]: In [31]: In [32]: seznam = [1, 2, 3] seznam seznam.append(4) seznam seznam.insert(2, 10) seznam Out[28]: [1, 2, 3] Out[30]: [1, 2, 3, 4] Out[32]: [1, 2, 10, 3, 4] Metoda extend(iterable) přidá na konec seznamu všechny prvky z jiného iterovatelného objektu In [33]: In [34]: seznam.extend([1, 2, 3]) seznam Out[34]: [1, 2, 10, 3, 4, 1, 2, 3] Odebírání prvkůOdebírání prvků Metoda pop() odebere poslední prvek a vrátí ho jako výsledek Metoda pop(i) odebere i-tý prvek a vrátí ho jako výsledek (následující prvky se posouvají o 1 doleva) In [35]: In [36]: In [37]: seznam x = seznam.pop() # Odstraň a vrať poslední prvek print(seznam, x) x = seznam.pop(2) # Odstraň a vrať druhý prvek print(seznam, x) Out[35]: [1, 2, 10, 3, 4, 1, 2, 3] [1, 2, 10, 3, 4, 1, 2] 3 [1, 2, 3, 4, 1, 2] 10 Metoda remove(prvek) odebere první výskyt prvku prvek (následující prvky se posouvají o 1 doleva) In [38]: In [39]: In [40]: seznam seznam.remove(2) # Odstraň prvek 2 seznam Out[38]: [1, 2, 3, 4, 1, 2] Out[40]: [1, 3, 4, 1, 2] Změna směruZměna směru In [41]: In [42]: In [43]: seznam seznam.reverse() seznam Out[41]: [1, 3, 4, 1, 2] Out[43]: [2, 1, 4, 3, 1] ŘazeníŘazení Metoda sort In [44]: In [45]: In [46]: In [47]: seznam = [1, 4, 2, -3, 5, 0] seznam.sort() seznam seznam.sort(reverse=True) seznam seznam = ['pes', 'kočka', 'slon'] seznam.sort() seznam seznam.sort(key=len) seznam Out[44]: [-3, 0, 1, 2, 4, 5] Out[45]: [5, 4, 2, 1, 0, -3] Out[46]: ['kočka', 'pes', 'slon'] Out[47]: ['pes', 'slon', 'kočka'] n-tice (-tice (tuple)) Neupravovatelný soubor n hodnot s daným pořadím Vytváříme je: pomocí () z jednotlivých prvků pomocí funkce tuple z jiného iterovatelného objektu n-tici nelze modi kovat Používáme, když jednotlivé prvky mají svůj speci cký význam a není nutné přidávat/odebírat prvky, např. adresa = (ulice, číslo, město) In [48]: adresa = ('Vlhká', 5, 'Brno') adresa Out[48]: ('Vlhká', 5, 'Brno') In [1]: In [50]: In [51]: souradnice = (1.0, 2.5) souradnice seznam ntice = tuple(seznam) ntice Out[1]: (1.0, 2.5) Out[50]: ['pes', 'slon', 'kočka'] Out[51]: ('pes', 'slon', 'kočka') IndexováníIndexování n-tic-tic Jako u řetězců a seznamů In [52]: In [53]: In [54]: In [55]: adresa = ('Vlhká', 5, 'Brno') adresa[0] adresa[1] adresa[2] adresa[:2] Out[52]: 'Vlhká' Out[53]: 5 Out[54]: 'Brno' Out[55]: ('Vlhká', 5) "Nultice" (empty tuple) In [56]: "Jednice" (singleton) In [57]: In [58]: Pozor na rozdíl mezi "jednicí" a samotným prvkem In [59]: nultice = () nultice jednice = (5,) jednice cislo = (5) cislo (5,) == 5 Out[56]: () Out[57]: (5,) Out[58]: 5 Out[59]: False Operace sOperace s n-ticemi-ticemi Jako u seznamů In [60]: In [61]: In [62]: In [63]: In [64]: cisla = (1, 2, 3) len(cisla) sum(cisla) cisla.count(8) cisla + cisla[::-1] cisla * 3 Out[60]: 3 Out[61]: 6 Out[62]: 0 Out[63]: (1, 2, 3, 3, 2, 1) Out[64]: (1, 2, 3, 1, 2, 3, 1, 2, 3) Množina (Množina (set)) Upravovatelný soubor unikátních hodnot bez daného pořadí Vytváříme je: pomocí {} z jednotlivých prvků pomocí funkce set z jiného iterovatelného objektu Množinu lze modi kovat Každý prvek obsažen nejvíc jednou Nelze indexovat In [65]: In [66]: mnozina = {1, 2, 3} mnozina mnozina = set('hello') mnozina Out[65]: {1, 2, 3} Out[66]: {'e', 'h', 'l', 'o'} Každý prvek je obsažen nejvíc jednou In [67]: Pořadí není dané In [68]: Nelze indexovat In [69]: seznam = [1, 1, 2, 3, 3] set(seznam) {1, 2, 3} == {3, 2, 1} mnozina = {1, 2, 3} mnozina[0] Out[67]: {1, 2, 3} Out[68]: True ------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () 1 mnozina = {1, 2, 3} ----> 2 mnozina[0] TypeError: 'set' object does not support indexing Prázdná množina se zapisuje set(), protože {} je rezervováno pro prázdný slovník In [70]: In [71]: type(set()) type({}) Out[70]: set Out[71]: dict Množinové operaceMnožinové operace len – počet prvků in, not in – přítomnost prvku (efektivnější než u seznamu, nemusí se kontrolovat všechny prvky) In [72]: In [73]: In [74]: In [75]: A = {1, 2, 3} len(A) 2 in A 5 in A Out[73]: 3 Out[74]: True Out[75]: False In [76]: In [77]: In [78]: In [79]: In [80]: In [81]: A = {1, 2, 3} B = {2, 4, 6} A & B # Průnik A ∩ B A | B # Sjednocení A ∪ B A - B # Rozdíl množin A - B (prvky A kromě prvků B) A <= B # A je podmnožinou B (A ⊆ B) A < B # A je vlastní podmnožinou B (A ⊂ B) Out[77]: {2} Out[78]: {1, 2, 3, 4, 6} Out[79]: {1, 3} Out[80]: False Out[81]: False Přidávání prvkůPřidávání prvků Metoda add In [82]: In [83]: A = set() A.add(5) A.add(6) A A.add(5) A Out[82]: {5, 6} Out[83]: {5, 6} Odebírání prvkůOdebírání prvků Metoda discard(x) odebere prvek x (neudělá nic, pokud tam x není) Metoda remove(x) odebere prvek x (skončí chybou, pokud tam x není) In [84]: In [85]: In [86]: A = set(range(5)) A A.discard(2) A Out[84]: {0, 1, 2, 3, 4} Out[86]: {0, 1, 3, 4} Metoda pop() odebere jeden libovolný prvek a vrátí ho jako výsledek In [87]: In [88]: In [89]: Metoda clear() odebere všechny prvky In [90]: In [91]: A x = A.pop() x A A.clear() A Out[87]: {0, 1, 3, 4} Out[88]: 0 Out[89]: {1, 3, 4} Out[91]: set() Slovník (Slovník (dict,, dictionary)) Upravovatelný soubor dvojic klíč:hodnota, bez daného pořadí Vytváříme je: pomocí {} z jednotlivých dvojic klíč:hodnota pomocí funkce dict z jiného iterovatelného objektu Slovník lze modi kovat Každý klíč obsažen nejvíc jednou Na pořadí nezáleží Indexujeme podle klíčů (ne podle pořadí) In [92]: In [93]: In [1]: slovnik = {'klic1': 'hodnota1', 'klic2': 'hodnota2'} slovnik slovnik = {} # Prázdný slovník slovnik seznam_dvojic = [('jack', 4098), ('sape', 4139), ('guido', 4127)] slovnik = dict(seznam_dvojic) slovnik Out[92]: {'klic1': 'hodnota1', 'klic2': 'hodnota2'} Out[93]: {} Out[1]: {'guido': 4127, 'jack': 4098, 'sape': 4139} Indexování slovníkuIndexování slovníku Pomocí klíče In [2]: In [3]: In [4]: slovnik slovnik['jack'] slovnik['bob'] Out[2]: {'guido': 4127, 'jack': 4098, 'sape': 4139} Out[3]: 4098 ------------------------------------------------------ KeyError Traceback (most recent call last) in () ----> 1 slovnik['bob'] KeyError: 'bob' Metoda get je jako [], ale řeší i chybějící klíče In [5]: In [6]: In [7]: print(slovnik.get('guido')) print(slovnik.get('bob')) print(slovnik.get('bob', 'defaultni_hodnota')) 4127 None defaultni_hodnota Testování přítomnosti klíčeTestování přítomnosti klíče U slovníku se pomocí in dotazujeme na klíče (ne na hodnoty) In [8]: In [9]: In [10]: In [11]: slovnik 'jack' in slovnik 4127 in slovnik 4127 in slovnik.values() Out[8]: {'guido': 4127, 'jack': 4098, 'sape': 4139} Out[9]: True Out[10]: False Out[11]: True Přidání nebo úprava stávajících hodnotPřidání nebo úprava stávajících hodnot Pokud klíč není ve slovníku, přidá se a přiřadí se mu hodnota Pokud klíč je ve slovníku, stará hodnota se zahodí a přiřadí se nová In [12]: In [13]: In [14]: slovnik slovnik['bob'] = 1234 slovnik slovnik['guido'] = 666 slovnik Out[12]: {'guido': 4127, 'jack': 4098, 'sape': 4139} Out[13]: {'bob': 1234, 'guido': 4127, 'jack': 4098, 'sape': 4139} Out[14]: {'bob': 1234, 'guido': 666, 'jack': 4098, 'sape': 4139} Metoda update přijímá jako parametr další slovník, kterým upraví stávající In [15]: In [16]: slovnik slovnik.update({'guido': 1111, 'alice': 9876}) slovnik Out[15]: {'bob': 1234, 'guido': 666, 'jack': 4098, 'sape': 4139} Out[16]: {'alice': 9876, 'bob': 1234, 'guido': 1111, 'jack': 4098, 'sape': 4139} Odebírání hodnotOdebírání hodnot Pomocí metody pop jako u seznamů In [17]: In [18]: Metoda clear vyprázdní celý slovník In [19]: slovnik x = slovnik.pop('jack') print(x, slovnik) slovnik.clear() slovnik Out[17]: {'alice': 9876, 'bob': 1234, 'guido': 1111, 'jack': 4098, 'sape': 4139} 4098 {'sape': 4139, 'guido': 1111, 'bob': 1234, 'alice': 9876} Out[19]: {} Homogenní a heterogenní kolekce, kolekce v kolekciHomogenní a heterogenní kolekce, kolekce v kolekci Homogenní kolekce – hodnoty stejného typu, [1, 2, 3] Heterogenní kolekce – hodnoty smíšeného typu, [1, 'ahoj', True] Kolekce mohou v sobě obsahovat další kolekce Výjimka: Klíče v slovníku a prvky množiny mohou být pouze nemodi kovatelné objekty. In [112]: In [113]: [1, '2', 3.0, [4, 5], (6, 7)] {'a': [(1,),(1,2)], 'b': [(2,3),(1,)], 'c': [(9,),(1,)], 'd':[]} Out[112]: [1, '2', 3.0, [4, 5], (6, 7)] Out[113]: {'a': [(1,), (1, 2)], 'b': [(2, 3), (1,)], 'c': [(9,), (1,)], 'd': []} ShrnutíShrnutí Seznam, list, [,,,] Více obdobných objektů v daném pořadí Chceme je přidávat/měnit/odebírat n-tice, tuple, (,,,) Více hodnot se speci ckým významem Nechceme měnit Množina, set, {,,,} Více obdobných objektů, na pořadí nám nezáleží Chceme efektivně přidávat/odebírat/testovat přítomnost prvků Slovník, dict, {:,:,:,:} Chceme si hodnoty asociovat s nějakým klíčem Chceme efektivně získat hodnotu pro daný klíč Další typy kolekcíDalší typy kolekcí Další specializované typy kolekcí nabízí modul collections: namedtuple defaultdict OrderedDict Counter frozenset deque ... Volba typu kolekceVolba typu kolekce Jaké typy kolekcí byste použili v těchto případech? Jaké budou typy hodnot (klíčů)? Každý den měříme teplotu vzduchu, chceme uložit naměřené hodnoty za celý měsíc. Měříme teplotu vzduchu 25.9. v Brně, Praze, Plzni a Ostravě. Ve třídě je několik studentů, u každého si chceme pamatovat jméno, příjmení a UČO. Vedeme si seznam zemí, které jsme navštívili. Čteme knihu a počítáme, kolikrát byla zmíněna každá z postav. Fakulta má několik ústavů, u každého si potřebujeme pamatovat jména zaměstnanců. Každý den měříme teplotu vzduchu, chceme uložit naměřené hodnoty za celý měsíc. Seznam reálných čísel Měříme teplotu vzduchu 25.9. v Brně, Praze, Plzni a Ostravě. Slovník (klíče str, hodnoty float) Ve třídě je několik studentů, u každého si chceme pamatovat jméno, příjmení a UČO. Seznam n-tic Vedeme si seznam zemí, které jsme navštívili. Množina řetězců Čteme knihu a počítáme, kolikrát byla zmíněna každá z postav. Slovník (klíče str, hodnoty int) Fakulta má několik ústavů, u každého si potřebujeme pamatovat jména zaměstnanců. Slovník (klíče str, hodnoty seznamy řetězců) Rozbalování (Rozbalování (unpacking)) Pomocí operátoru * Vytáhneme všechny prvky z iterovatelného objektu In [114]: In [115]: In [116]: In [117]: seznam = [1, 2, 3, 4] print(seznam) print(*seznam) # Stejné jako print(1, 2, 3, 4) [0, seznam, 5, 6] [0, *seznam, 5, 6] # Stejné jako [0, 1, 2, 3, 4, 5, 6] [1, 2, 3, 4] 1 2 3 4 Out[116]: [0, [1, 2, 3, 4], 5, 6] Out[117]: [0, 1, 2, 3, 4, 5, 6] Pomocí více proměnných na levé straně přiřazení In [118]: In [119]: In [120]: In [121]: In [122]: seznam a, b, c, d = seznam a b c d Out[118]: [1, 2, 3, 4] Out[119]: 1 Out[120]: 2 Out[121]: 3 Out[122]: 4 In [123]: In [124]: In [125]: In [126]: prvni, druhy, *zbytek, posledni = range(10) prvni druhy zbytek posledni Out[123]: 0 Out[124]: 1 Out[125]: [2, 3, 4, 5, 6, 7, 8] Out[126]: 9 Procházení kolekcíProcházení kolekcí Pomocí cyklu for In [127]: for prvek in {1, 2, 3, 2}: print(prvek) 1 2 3 Procházení slovníkůProcházení slovníků Přes klíče In [128]: In [129]: Přes hodnoty In [130]: Přes klíče a hodnoty In [131]: slovnik = {'guido': 4127, 'jack': 4098} for jmeno in slovnik: print(jmeno) for telefon in slovnik.values(): print(telefon) for jmeno, telefon in slovnik.items(): print(f'{jmeno}: {telefon}') guido jack 4127 4098 guido: 4127 jack: 4098 Chytré procházení kolekcíChytré procházení kolekcí Funkce enumerate očísluje prvky In [132]: In [133]: jmena = ['Bob', 'Alice', 'Cyril'] for i, jmeno in enumerate(jmena): print(f'{i}. {jmeno}') for i, jmeno in enumerate(jmena, 1): print(f'{i}. {jmeno}') 0. Bob 1. Alice 2. Cyril 1. Bob 2. Alice 3. Cyril Funkce reversed prochází od konce In [134]: Funkce sorted prochází vytváří nový seřazený seznam In [135]: Funkce zip prochází více objektů najednou In [136]: for jmeno in reversed(jmena): print(jmeno) for jmeno in sorted(jmena): print(jmeno) for jmeno, pismenko in zip(jmena, 'XYZW'): print(jmeno, pismenko) Cyril Alice Bob Alice Bob Cyril Bob X Alice Y Cyril Z Pozor, funkce enumerate, reversed, zip nevytváří kolekci, pouze iterátor určen k jednorázovému projdění prvků In [137]: In [138]: iterator = reversed(jmena) for jmeno in iterator: print(jmeno) for jmeno in iterator: print(jmeno) Cyril Alice Bob Generátorové výrazy (Generátorové výrazy (generator expression)) Pomocí ...for...in... můžeme vytvářet a ltrovat kolekce In [139]: In [140]: In [141]: Filtrujeme přidáním if In [142]: puvodni = [1, 2, 3, 4, 5, 6] [str(x) for x in puvodni] {i: i**2 for i in puvodni} {x for x in puvodni if x % 2 == 0} Out[140]: ['1', '2', '3', '4', '5', '6'] Out[141]: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36} Out[142]: {2, 4, 6} Typ výsledné kolekce je dán typem závorek: [] seznam, {} množina nebo slovník Výjimka: () vytváří iterátor, nikoliv n-tici In [143]: In [144]: (x for x in puvodni if x >= 3) # iterátor tuple(x for x in puvodni if x >= 3) # n-tice Out[143]: at 0x7f887c3b09e8> Out[144]: (3, 4, 5, 6) FunkceFunkce join Spojuje prvky pomocí separatorů, funguje ale pouze na prvky typu str In [145]: iterable = ['1', '2', '3'] ' - '.join(iterable) Out[145]: '1 - 2 - 3' Vytvoření nového objektu vs modi kace objektuVytvoření nového objektu vs modi kace objektu Vytvoření nového objektu: In [146]: In [147]: puvodni = 'Spam spam spam.' novy = puvodni.replace('spam', 'ham') print(puvodni) print(novy) puvodni = [1, 8, 5, 2] novy = sorted(puvodni) print(puvodni) print(novy) Spam spam spam. Spam ham ham. [1, 8, 5, 2] [1, 2, 5, 8] Modi kace objektu: In [148]: In [149]: puvodni = [1, 8, 5, 2] novy = puvodni.sort() print(puvodni) print(novy) puvodni = [1, 8, 5, 2] novy = puvodni.append(0) print(puvodni) print(novy) [1, 2, 5, 8] None [1, 8, 5, 2, 0] None Stejné objekty vs ten samý objektStejné objekty vs ten samý objekt Operátory ==, != testují, jestli jsou dva objekty stejné Operátory is, is not testují, jestli se jedná o ten samý objekt Dva stejné objekty: In [150]: In [151]: In [152]: a = [1, 2, 3] b = [1, 2, 3] a == b a is b a.append(4) print(a, b) Out[150]: True Out[151]: False [1, 2, 3, 4] [1, 2, 3] Ten samý objekt: In [153]: In [154]: In [155]: a = [1, 2, 3] b = a a == b a is b a.append(4) print(a, b) Out[153]: True Out[154]: True [1, 2, 3, 4] [1, 2, 3, 4] Všechny modi kovatelné kolekce můžeme duplikovat pomocí metody copy (vytváříme tak nový objekt) In [156]: a = [6, 8, 3, 1] b = a.copy() b.sort() print(a, b) [6, 8, 3, 1] [1, 3, 6, 8]