11. diel - Vnorené zoznamy v Dart
V predchádzajúcom cvičení, Riešené úlohy k 10. lekcii Dart, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulej lekcii, Riešené úlohy k 10. lekcii Dart , sme si uviedli metódy split()
a
join()
na textových reťazcoch. Dnešné Dart tutoriál pojednáva
o tzv. Viacrozmerných poliach, pre nás konkrétne o vnorených zoznamoch.
Už vieme pracovať s jednorozmernými poľom (zoznamom), ktoré si môžeme predstaviť ako riadku priehradok v pamäti počítača.
(Na obrázku je vidieť pole ôsmich čísiel)
Hoci to nie je tak časté, v programovaní sa občas stretávame aj s viacrozmernými poliami a to najmä ak programujeme nejakú simuláciu (napr. Hru).
Dvojrozmerné pole
Dvojrozmerné pole si môžeme v pamäti predstaviť ako tabuľku a mohli by sme takto reprezentovať napr. Rozohranú partiu piškvoriek. Ak by sme sa chceli držať reálnych aplikácií, ktoré budete neskôr v zamestnaní tvoriť, môžeme si predstaviť, že do 2D poľa budeme ukladať informácie o obsadenosť sedadiel v kinosály. Situáciu by sme si mohli graficky znázorniť napr. Nasledovne:
(Na obrázku je vidieť 2d pole reprezentujúci obsadenosť kinosály)
Kinosála by bol v praxi samozrejme väčší, ale ako ukážka nám toto
pole postačí. Hodnota 0
označuje voľno, 1
obsadené. Neskôr by sme mohli doplniť aj 2
- Rezervované a
podobne. Pre tieto stavy by bolo správnejšie vytvoriť si vlastný dátový
typ, tzv. Výpočet, ale s ním sa stretneme až neskôr, takže si teraz
musíme vystačiť iba s číslami.
Pripomeniem, že pole je pre nás v Dart zoznam. Vnorený zoznam v Dart deklarujeme nasledujúcim spôsobom:
List<List<int>> kinosal = [];
V tomto prípade chceme kinosála na začiatku definovať do určitého
tvaru. To docielime tak, že by sme vo for
cykle pridali do zoznamu
zoznamy, do ktorých by sme pridali danej hodnoty. Alebo použijeme
sofistikovanejšie zápis, ktorý sa pre jeho momentálnej náročnosť v rámci
tohto tutoriálu nebudeme snažiť vysvetliť.
List<List<int>> kinosal = new List.generate(5, (_) => new List.filled(5, 0));
Popíšem kód aspoň jednoducho, aj keď zatiaľ nevieme, prečo to takto funguje: vytvoríme si zoznam, ktorý v sebe vygeneruje 5x zoznam, ktorý v sebe má 5x číslo 0.
Prvá číslica udáva počet stĺpcov, druhá počet riadkov (samozrejme si to môžeme určiť aj obrátene, napr. Matice v matematike sa zapisujú opačne).
Naplnenie dátami
Teraz kinosála naplníme jednotkami tak, ako je vidieť na obrázku
vyššie. Pretože budeme ako správni programátori leniví, využijeme na
vytvorenie riadku jedničiek for
cykly.:) Pre prístup k prvku
zoznamu musíme samozrejme zadať 2 súradnice. Vypíšeme si tiež obsah
kinosály pred a po:
print(kinosal); kinosal[2][2] = 1; // Prostředek for (int i = 1; i < 4; i++) // 4. řádek { kinosal[i][3] = 1; } for (int i = 0; i < 5; i++) // Poslední řádek { kinosal[i][4] = 1; } print(kinosal);
Výstup programu:
Konzolová aplikácia
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 0, 1, 1, 1], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1]]
Ako ide vidieť, jedničky sa nám niekde zapísali a ak porovnáme výstup s obrázkom vyššie, naozaj sa všetko i zhoduje.
Výpis
Výpis pole opäť vykonáme pomocou cyklu, na vnorený budeme potrebovať
cykly 2 (jeden nám proiteruje stĺpce a druhý riadky). Ako správni
programátori nevložíte počet riadkov a stĺpcov do cyklov napevno, pretože
sa môže zmeniť. Využijeme vlastnosti length
na zozname. Pozor
ale, že vráti počet prvkov v konkrétnom zozname, nie celkový počet. Výraz
kinosal.length
nám vráti počet stĺpcov,
kinosal.first.length
vráti počet sedadiel v prvom stĺpci.
Keďže v našom kine majú všetky stĺpce rovnaký počet sedadiel, môžeme
druhú hodnotu brať ako počet radov sály.
for (int j = 0; j < kinosal.length; j++) { for (int i = 0; i < kinosal.first.length; i++) { stdout.write(kinosal[i][j]); } stdout.writeln(); }
Výstup programu:
Konzolová aplikácia
00000
00000
00100
01110
11111
Aj náš výpis vnoreného zoznamu dopadol dobre. Podobne by sme takto mohli tvoriť aj viac zanorené zoznamy, stačilo by do položiek vnoreného zoznamu vygenerovať ďalšie zoznamy. Celok si potom môžeme predstaviť ako by kinosála mal ešte ďalšie poschodia.
Zoznam zoznamov
Niekedy nepožadujeme všetky zoznamy v zozname rovnako veľké, výsledkom bude "zubatý" zoznam zoznamov ako na obrázku nižšie.
Výhodou je, že do každého riadku / stĺpca môžeme uložiť ako veľký zoznam chceme. V niektorých prípadoch teda nemusíme "plytvať" pamäťou na celú tabuľku a môžeme zoznam vytvoriť takto "zubato" (anglicky Jagged).
Takýto zoznam vytvoríme jednoducho pomocou deklarácie, ktorú sme už raz skúšali:
List<List<int>> kinosal = [];
Nevýhodou tohto prístupu je, že si všetky hodnoty musíme vložiť sami a musíme tiež kontrolovať, že prvok, ktorý chceme získať, naozaj existuje.
Ručné inicializácia vnorených zoznamov
Ešte si ukážeme, že aj pre vnorené zoznamy je možné použiť definíciu formou doslovný:
List<List<int>> kinosal = [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 0, 1, 1, 1], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1], ];
(Pole je v tejto zápisnici otočené, keďže definujeme stĺpce, ktoré tu zapisujeme ako riadky).
Na záver by som rád dodal, že niektorí ľudia, ktorí nevie správne
používať objekty, využívajú vnorené zoznamy na ukladanie viac údajov o
jedinej entite. Napr. budeme chcieť uložiť výšku, šírku a dĺžku piatich
mobilných telefónov. Hoci sa vám teraz môže zdať, že sa jedná o úlohu
na 3D pole, v skutočnosti sa jedná o úlohu na obyčajné 1D pole (presnejšie
zoznam) objektov typu Telefon
. Ale o tom až u objektovo
orientovaného programovania.
V budúcej lekcii, Matematické funkcie v Dart a knižnica dart: math , sa pozrieme na matematické funkcie.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 10x (1.78 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Dart