V předchozím výkladu jsme si řekli, že seznamy jsou datové kontejnery skládající se z prvků jiných datových typů. Nyní si ukážeme, že samotné prvky seznamu mohou být také seznamy.
Představme si například, že základní údaje o členech fotbalového mužstva budeme ukládat do seznamu o 5 prvcích - jméno, příjmení, číslo, pozice, rok narození, např.
hrac1 = ['Petr', 'Nápravník', 5, 'obránce', 1993] hrac2 = ['Jan', 'Horký', 7, 'brankář', 1996] hrac3 = ['Karel', 'Wedlich', 14, 'záložník', 1997] hrac4 = ['Miroslav', 'Nagy', 11, 'útočník', 1993]
Pak bychom část mužstva mohli uložit do seznamu
fc_lhota = [hrac1, hrac2, hrac3, hrac4]
což ale vlastně není nic jiného než
fc_lhota = [ ['Petr', 'Nápravník', 5, 'obránce', 1993], ['Jan', 'Horký', 7, 'brankář', 1996], ['Karel', 'Wedlich', 14, 'záložník', 1997], ['Miroslav', 'Nagy', 11, 'útočník', 1993]]
Definice seznamu tvoří jeden logický řádek programu, všimněte si však, že výčet položek může za čárkou pokračovat pro lepší přehlednost na dalším fyzickém řádku bez dalších speciálních znaků.
Dobře víme, že k prvkům seznamu lze přistupovat pomocí indexů, známe některé funkce pro práce se seznamy. Následující výrazy pak mají dobrý smysl a význam a je z nich mimo jiné vidět, jak funguje vícenásobné indexování.
# data hráče klubu FC Lhota s indexem 1 fc_lhota[1] # => ['Jan', 'Horký', 7, 'brankář', 1996] # pozice na hřišti tohoto hráče (fc_lhota[1])[3] # => 'brankář' # totéž lze i jednodušeji bez kulatých závorek fc_lhota[1][3] # => 'brankář' # počet hráčů klubu len(fc_lhota) # => 4 # počet údajů o hráči s indexem 1 len(fc_lhota[1]) # => 5 # délka řetězce popisující pozici určeného hráče len(fc_lhota[1][3]) # => 7
Pokud si uvědomíme, že např. jméno a příjmení hráče (položky seznamu s indexy 0 a 1) jsou řetězce, jejichž jednotlivé znaky je také možné indexovat, pak nás již nepřekvapí, že pomocí fragmentu kódu
for hrac in fc_lhota: print(hrac[0][0], hrac[1][0], sep = '', end = ' ') print()
vypíšeme na jeden řádek iniciály všech hráčů - výsledek je PN JH KW MN
. Stačí si uvědomit, že hrac[0]
je vlastně jméno hráče a hrac[0][0]
je první písmeno tohoto jména (analogicky pro hrac[1]
jako příjmení). Podobně výraz fc_lhota[-1][1][0]
nabývá hodnoty N
- jde o posledního hráče seznamu (1. index je -1
), v něm nás zajímá příjmení (2. index je 1
) a z něj vezmeme pouze počáteční znak (3. index je 0
).
Uvedený seznam fc_lhota
je vlastně jakousi databází hráčů fotbalového klubu, kterou můžeme následně podle potřeby zpracovávat - vybrat všechny obránce, vypsat jména hráčů v pořadí dle věku nebo čísla dresu apod. Samozřejmě lze využívat všechny postupy, metody, operátory atd. jako pro všechny ostatní seznamy.
Již u běžných (tj. jednorozměrných) seznamů jsme uváděli, že velmi často jsou všechny prvky stejného datového typu a pak hovoříme o polích. Pokud máme seznam, kde každá položka je seznamem řekněme float
čísel, nazveme jej analogicky dvourozměrným polem. Nejčastěji jsou délky podseznamů shodné, potom taková datová struktura vlastně reprezentuje matici reálných čísel, jejíž položky jsou odkazovány pomocí dvojice indexů. Obvykle prvním indexem číslujeme řádky matice, druhým indexem sloupce.
V matici reálných čísel o 4 řádcích a 3 sloupcích
matice = [ [0.15, 0.67, 0.48], [0.25, 0.91, 0.08], [0.19, 0.14, 0.64], [0.56, 0.07, 0.83]]
nabývá první index (řádkový) hodnot 0 až 3, druhý index (sloupcový) hodnot 0 až 2 a prvek matice[2][1]
má hodnotu 0.14
. K určení konkrétního prvku tedy potřebujeme dva nezávislé indexy.
Stejně jako matice v matematice, tak i dvojrozměrná pole v programování nalézají použití v mnoha situacích, např. lze pomocí nich snadno uložit aktuální stav partie na šachovnici či piškvorkové bitvy. Dvojrozměrným polem je i obrazovka vašeho počítače. Ta je rozdělena na pixely, každému z nich je přiřazena nějaká barva a jeho poloha je určena řádkovým a sloupcovým indexem.
Představme si mini kinosál o 4 řadách a 6 sedadlech v každé řadě. Rezervační systém by aktuální obsazenost mohl sledovat pomocí dvojrozměrného pole kinosal
logických hodnot (True
pro obsazené sedadlo) o 4 řádcích (odpovídají řadám) a 6 sloupcích (odpovídají sedadlům za sebou).
Pak počet obsazených sedadel v poslední řadě a počet všech krajních obsazených sedadel určíme např. takto.
# 'kinosal' je 2D pole typu 'bool' kinosal = [ [True, False, False, False, True, True], [True, True, False, False, False, False], [False, True, True, False, False, False], [True, True, True, False, False, False]] # počet obsazených sedadel v poslední řadě posl_rada = kinosal[-1].count(True) # 'kinosal[-1]' je seznam reprezentující poslední řadu # metoda 'count' (má každý seznam) určí počet obsazených sedadel # pocet obsazených sedadel na obou krajích krajnich = 0 for rada in kinosal: # procházíme všechny řady kinosálu # 'rada' je 1D seznam o 6 prvcích typu 'bool' if rada[0]: krajnich += 1 # obsazené sedadlo na jednom kraji if rada[-1]: krajnich += 1 # obsazené sedadlo na opačném kraji # výsledky print("Obsazeno v poslední řadě:", posl_rada) print("Obsazeno na krajích:", krajnich)
Máme-li více dvojrozměrných polí stejného typu, můžeme je opět uložit do seznamu a vznikne nám trojrozměrné pole. Na konkrétní prvek se pak odkazujeme pomocí 3 indexů. V tomto postupu bychom mohli postupovat i nadále (ke čtyř- a vícerozměrným polím), ale praktické použití takovýchto polí je již výrazně menší než u dvojrozměrných.