Lekce 8 - Seznamy v Dartu
V minulé lekci kurzu, Ošetření uživatelských vstupů v Dartu, jsme si ukázali ošetření uživatelských vstupů. Dnes si v tutoriálu programovacího jazyka Dart představíme datovou strukturu seznam a vyzkoušíme si, co všechno umí.
Seznam
Představte si, že si chcete uložit nějaké údaje o více prvcích.
Např. chcete v paměti uchovávat 10 čísel, políčka šachovnice nebo jména
50ti uživatelů. Asi vám dojde, že v programování bude nějaká lepší
cesta, než začít bušit proměnné uzivatel1
,
uzivatel2
... až uzivatel50
. Nehledě na to, že jich
může být třeba 1000. A jak by se v tom potom hledalo? Brrr, takhle ne.
Pokud potřebujeme uchovávat větší množství proměnných
stejného typu, tento problém nám řeší seznam. Můžeme si ho
představit jako řadu přihrádek, kde v každé máme uložený jeden prvek.
Přihrádky jsou očíslované tzv. indexy, první má index 0
.
Programovací jazyky se velmi liší v tom, jak s podobnými datovými strukturami pracují. V některých jazycích (zejména starších, kompilovaných) nebylo možné za běhu programu vytvořit seznam s dynamickou velikostí (např. mu dát velikost dle nějaké proměnné). Takovým seznamům se říká pole. Pole se muselo deklarovat s konstantní velikostí přímo ve zdrojovém kódu. Toto se obcházelo tzv. pointery a vlastními datovými strukturami, což často vedlo k chybám při manuální správě paměti a nestabilitě programu (např. v C++). Naopak některé interpretované jazyky umožňují nejen deklarovat seznam s libovolnou velikostí, ale dokonce tuto velikost na již existujícím seznamu měnit (např. PHP). Jak jsem již říkal, v Dartu je vše objekt. V rámci tohoto kurzu nám bude stačit vědět, co to seznam obecně je a že kolekce jsou chytré datové struktury, které nám usnadňují práci. O kolekcích jako takových si něco povíme až v kurzu o Objektovém programování v Dart.
Seznam je jednoduchý, prvky jsou za sebou a můžeme je snadno procházet. Pro hromadnou manipulaci s prvky seznamu se používají cykly. To samé platí i pro seznamy v Dartu, proto jsou ideálním kandidátem, kterého budeme používat.
Seznam deklarujeme jako List (což je seznam anglicky) a do špičatých závorek přidáme typ položek seznamu.
List<int> seznam;
Seznam je samozřejmě název naší proměnné. Nyní jsme však pouze
deklarovali, že v proměnné bude seznam intů. Nyní ho musíme založit,
abychom ho mohli používat. K tomu buď využijeme literál (možnost, jak
explicitně něco zapsat, např. 3 pro celočíselný literál). Literál pro
seznam je [ ]
, nebo použijeme klíčové slovo new
,
které se využívá u složitějších objektů, což si vysvětlíme
podrobněji v již zmíněném navazujícím kurzu.
List<int> seznam = []; List<int> seznam2 = new List();
Nyní máme v proměnné seznam
a seznam2
seznamy,
které se samy zvětšují či zmenšují podle potřeb.
Do seznamu přidáváme prvky metodou add()
, která jako
parametr bere daný prvek. K prvkům seznamů přistupujeme přes hranatou
závorku, do které píšeme index daného prvku (ten musí
existovat).
seznam.add(1); print(seznam[0]);
Plnit seznam takhle ručně by bylo příliš pracné, použijeme cyklus a
naplníme si seznam čísly od 1 do 10. K naplnění použijeme for
cyklus:
for (int i = 0; i < 10; i++) seznam.add(i + 1);
Abychom seznam vypsali, můžeme za předchozí kód připsat:
for (int i = 0; i < seznam.length; i++) print(seznam[i]);
Výstup programu:
Konzolová aplikace
1
2
3
4
5
6
7
8
9
10
Všimněte si, že seznam má vlastnost length
, kde je uložena
jeho délka, tedy počet prvků.
A nebo, protože jak jsem zmiňoval, seznam v Dartu je kolekce a ta se umí
sama vypsat, můžeme vypsat celý seznam najednou pomocí metody
print()
:
print(seznam);
Výstup programu:
Konzolová aplikace
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Můžeme použít zjednodušenou verzi cyklu pro práci s kolekcemi, známou jako foreach. Ten projede všechny prvky v seznamu a jeho délku si zjistí sám. Jeho syntaxe pro náš seznam je následující:
for (datovytyp promenna in kolekce) { // příkazy }
Kolekce v Dartu mají navíc metody na zjednodušený zápis foreach cyklu a dalších speciálních cyklů.
kolekce.forEach((datovytyp promenna) {
// příkazy
});
Cyklus projede prvky v kolekci (to je obecný název pro struktury, které obsahují více prvků, u nás to bude seznam) postupně od prvního do posledního. Prvek máme v každé iteraci cyklu uložený v dané proměnné.
Přepišme tedy náš dosavadní program na metodu forEach()
.
Foreach nemá řídící proměnnou, není tedy vhodný pro vytvoření našeho
seznamu a použijeme ho jen pro výpis.
seznam.forEach((int promenna) { stdout.write('$promenna '); });
Výstup programu:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
Seznam samozřejmě můžeme naplnit ručně a to i bez toho, abychom prvky postupně dosazovali. Použijeme k tomu literál seznamu, který jsem zmiňoval již dříve, a prvky v něm oddělíme čárkou:
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie'];
Seznam často slouží k ukládání mezivýsledků, které se potom dále v programu používají. Když potřebujeme nějaký výsledek 10x, tak to nebudeme 10x počítat, ale spočítáme to jednou a uložíme do seznamu, odtud poté výsledek jen načteme.
Metody a vlastnosti na třídě List
Samotný List obsahuje řadu užitečných metod a vlastností pro práci se seznamy. Pojďme se na ně podívat:
sort()
Jak již název napovídá, metoda nám seznam seřadí. Její jediný
parametr je komparátor, speciální metoda, která určí, jak položky v
seznamu setřídit. String
má v Dartu metodu, která porovná sebe
vůči jinému Stringu. Tuto metodu využijeme. Zkusme si setřídit a vypsat
naši rodinku Simpsnů:
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie']; print(simpsonovi); simpsonovi.sort((String a, String b) => a.compareTo(b)); print(simpsonovi);
Výstup programu:
Konzolová aplikace
[Homer, Marge, Bart, Lisa, Meggie]
[Bart, Homer, Lisa, Marge, Meggie]
Zkuste si vytvořit seznam čísel a vyzkoušejte si, že to opravdu funguje
i pro ně. Stejně tak i int
má metodu
compareTo()
.
reversed
Vlastnost reversed
nám vrátí otočený seznam (první prvek
bude jako poslední atd.), toho můžeme využít např. pro třídění
pozpátku. Tato vlastnost nevrací seznam, ale obecnou kolekci, kterou lze
procházet. Pokud bychom chtěli vrátit seznam, na vlastnost
reversed
zavoláme ještě metodu toList()
.
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie']; simpsonovi.sort((String a, String b) => a.compareTo(b)); print(simpsonovi.reversed); print(simpsonovi.reversed.toList());
Výstup programu:
Konzolová aplikace
(Meggie, Marge, Lisa, Homer, Bart)
[Meggie, Marge, Lisa, Homer, Bart]
indexOf() a lastIndexOf()
Tyto metody vrátí index prvního nebo posledního nalezeného prvku. V
případě nenalezení prvku vrátí -1. Každá z metod bere dva parametry,
prvním je hledaný prvek, druhý nepovinný parametr je index, od kterého
začít. Umožníme uživateli zadat jméno Simpsna a řekneme mu, na jaké
pozici je uložený. Teď to pro nás nemá hlubší význam, protože prvek
seznamu je jen String
. Bude se nám to však velmi hodit ve
chvíli, kdy v poli budeme mít uloženy plnohodnotné objekty. Berme to tedy
jako takovou přípravu.
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie']; print('Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsnů): '); String simpson = stdin.readLineSync(encoding: UTF8); int pozice = simpsonovi.indexOf(simpson); if (pozice >= 0) print('Jo, to je můj ${pozice + 1}. nejoblíbenější Simpson!'); else print('Hele, tohle není Simpson!');
Výstup programu:
Konzolová aplikace
Ahoj, zadej svého oblíbeného Simpsna (z rodiny Simpsnů):
Homer
Jo, to je můj 1. nejoblíbenější Simpson!
sublist()
Sublist vrací výřez seznamu od startovního indexu do konce nebo do koncového indexu, přičemž tento index se ve výřezu již neobjeví.
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie']; print(simpsonovi.sublist(2, 4));
Výstup programu:
Konzolová aplikace
[Bart, Lisa]
length
Vlastnost length
jsme si již zmínili, vrátí délku seznamu.
Není metodou, ale vlastností, nepíší se za ni tedy závorky ().
first a last
Vlastnosti vracející první a poslední prvek seznamu.
take() a skip()
Obě tyto metody berou jako parametr počet prvků. Take vrátí seznam s daným počtem prvků zkopírovaných od začátku původního seznamu. Skip() naopak vrátí seznam bez těchto prvních prvků.
contains()
Metoda vrací true
/false
podle toho, zda se prvek,
uvedený v parametru metody, v daném poli nachází.
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie']; print(simpsonovi.contains('Bart')); print(simpsonovi.contains('Superman'));
Výstup programu:
Konzolová aplikace
true
false
shuffle()
Shuffle() je metoda, která náhodně prohází prvky seznamu. Nic nevrací, operuje nad konkrétním seznamem, kterému v zásadě jen prohází indexy.
List<String> simpsonovi = ['Homer', 'Marge', 'Bart', 'Lisa', 'Meggie']; print(simpsonovi); simpsonovi.shuffle(); print(simpsonovi); simpsonovi.shuffle(); print(simpsonovi);
Výstup programu:
Konzolová aplikace
[Homer, Marge, Bart, Lisa, Meggie]
[Bart, Marge, Lisa, Homer, Meggie]
[Homer, Bart, Marge, Meggie, Lisa]
To by pro dnešek stačilo, můžete si se seznamem hrát. V příští lekci, Řešené úlohy k 7.-8. lekci Dartu, na vás čeká překvapení.
V následujícím cvičení, Řešené úlohy k 7.-8. lekci Dartu, si procvičíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 6x (2.15 kB)
Aplikace je včetně zdrojových kódů v jazyce Dart