IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

12. diel - Kolekcia Set, Queue a Map v Dart

V minulej lekcii, Dátum a čas v Dart , sme si povedali niečo o dátume a času v Dart. V dnešnom tutoriále si ukážeme ďalšie kolekcie, ktoré máme dostupné as ktorých položkami môžeme pracovať inak ako chcete v nám už známom zozname.

Pojem kolekcia sme tu už spomenuli. Je to štruktúra, do ktorej môžeme ukladať viac objektov. Kolekcií je v Dart niekoľko, sú prispôsobené pre rôzne účely a môžeme s nimi zaobchádzať rôznymi spôsobmi. Doteraz poznáme iba kolekciu zoznam (List). V priebehu kurzu však budeme potrebovať aj ďalšie kolekcie, ktoré si dnes vysvetlíme.

Set

Set je kolekcia reprezentujúci množinu, ktorá si je veľmi podobná s List, avšak zásadným rozdielom je, že každý objekt sa v nej môže vyskytovať iba raz, tj. Neuchováva duplicity. Množinu možno ľahko previesť na zoznam a zoznam na množinu pomocou metódy toSet() či toList(). Ľahko tak možno z listu odstrániť duplicity pomocou zreťazenie týchto metód, napr. mujList.toSet().toList().

Vyskúšajme si ju:

Set<int> set = new Set();
set.add(1);
set.add(1);
set.add(2);
set.add(1);
print(set);

Výstup programu:

Konzolová aplikácia
{1, 2}

Pre každý objekt zadaného typu možno určiť, či je alebo nie je v množine. Ak začneme množinu prechádzať, budú prvky v takom poradí, v akom boli pridané. Prvky sa rozlišujú podľa operátora == a je odporúčané, ak je tento operátor prepísaný, taktiež prepísať aj metódu hashCode() pre zachovanie konzistencie.

Množina má taktiež oproti zoznamu niekoľko špecifických funkcií:

union()

Metóda množinového zjednotenie, ktorá vracia novú množinu s prvkami z prvej aj z druhej množiny. Druhú množinu odovzdáme parametrom. Najprv sú pridané prvky z prvej množiny v pôvodnom poradí a následne sú pridané zvyšné prvky, ktoré sú v druhej množine navyše, v poradí z druhej množiny.

Set<int> a = new Set();
a.addAll([1, 2, 1, 1, 2, 4]);
Set<int> b = new Set();
b.addAll([1, 2, 2, 2, 2, 3, 3, 5]);

print(a);
print(b);
print(a.union(b));
print(b.union(a));

Výstup programu:

Konzolová aplikácia
{1, 2, 4}
{1, 2, 3, 5}
{1, 2, 4, 3, 5}
{1, 2, 3, 5, 4}

difference()

Ďalšou zaujímavou metódou je Množinový rozdiel. Metóda vráti novú množinu s prvkami z prvej množiny, ktoré sa nevyskytovali v druhej množine. Druhú množinu opäť odovzdáme parametrom.

Set<int> a = new Set();
a.addAll([1, 2, 1, 1, 2, 4]);
Set<int> b = new Set();
b.addAll([1, 2, 2, 2, 2, 3, 3, 5]);

print(a);
print(b);
print(a.difference(b));
print(b.difference(a));

Výstup programu:

Konzolová aplikácia
{1, 2, 4}
{1, 2, 3, 5}
{4}
{3, 5}

intersection()

Posledný z množinových metód je Množinový prienikom. Metóda vráti novú množinu obsahujúce iba prvky, ktoré boli spoločné v oboch množinách.

Set<int> a = new Set();
a.addAll([1, 2, 1, 1, 2, 4]);
Set<int> b = new Set();
b.addAll([1, 2, 2, 2, 2, 3, 3, 5]);

print(a);
print(b);
print(a.intersection(b));
print(b.intersection(a));

Výstup programu:

Konzolová aplikácia
{1, 2, 4}
{1, 2, 3, 5}
{1, 2}
{1, 2}

Vlastný objekt

Ako už bolo povedané, ak chceme pracovať s množinou, objekt musí mať implementovaný operátor == a metódu hashCode(). Pre ukážku si vytvoríme objekt Auto, ktoré bude mať rýchlosť a názov. Následne vytvoríme 3 autá, pričom 2 z nich budú mať rovnaké hodnoty:

class Auto {
    int rychlost;
    String nazev;

    @override
    String toString() {
        return '$nazev($rychlost)';
    }
}

void main() {
    Auto mazel = new Auto()
        ..nazev = 'Mazlík'
        ..rychlost = 150;
    Auto auto = new Auto()
        ..nazev = 'Mazlík'
        ..rychlost = 150;
    Auto popelnice = new Auto()
        ..nazev = 'Šunka'
        ..rychlost = 60;

    Set<Auto> auta = new Set();
    auta.add(mazel);
    auta.add(auto);
    auta.add(popelnice);
    print(auta);
}

Výstup programu:

Konzolová aplikácia
{Mazlík(150), Mazlík(150), Šunka(60)}

Očakávané správanie je samozrejme také, že keď používame množinu, mali by v nej byť vo výsledku len 2 autá, pretože uchováva len unikátne objekty. Avšak hľa - auto, ktoré identifikujeme podľa názvu a rýchlosti, sa nám objavilo dvakrát. Zabudli sme implementovať operátor == a hashCode(). Nemusíme vymýšľať relatívne zložitý kód sami, IDE nám ho vygeneruje za nás. Stačí stlačiť klávesy ALT + INSERT (Generate ...) a zvoliť ==() and hashCode.

Objektovo orientované programovanie v Dart

My budeme chcieť identifikovať naše auto podľa názvu a rýchlosti, preto zvolíme obe vlastnosti.

@override
bool operator ==(Object other) =>
    identical(this, other) ||
    other is Auto && runtimeType == other.runtimeType && rychlost == other.rychlost && nazev == other.nazev;

@override
int get hashCode => rychlost.hashCode ^ nazev.hashCode;

Všimnite si novinky, kľúčového slova operator. Presne tak možno prepísať takmer ľubovoľný operátor pre daný objekt. K preťažovanie operátorov sa ešte vrátime a vysvetlíme si všetko viac do hĺbky. Znovu si spustíme náš program, tentoraz už všetko funguje presne tak, ako by sme očakávali:

Konzolová aplikácia
{Mazlík(150), Šunka(60)}

Queue

Queue je kolekcia, ktorá opäť veľmi pripomína zoznam, avšak reprezentuje front (FIFO) a zásobník (LIFO). To znamená, že je táto kolekcia optimalizovaná na prístup na prvý či posledný prvok. Pre používanie je nutné importovať knižnicu dart:collection. Rovnako ako zoznam alebo množina, aj front možno prechádzať a bude fungovať aj prístup na položku na danom indexe, avšak kvôli implementácii frontu nebude prístup tak rýchly ako v zoznamoch.

Vyskúšame si jednoduchú ukážku:

Queue<int> queue = new Queue();
queue.add(1);
queue.add(2);
queue.add(2);
queue.add(3);
print(queue);

Doteraz je správanie rovnaké so zoznamom. Ukážeme si však ďalšie metódy pre prácu s frontom.

addLast()

Metóda pre vloženie prvku na koniec fronty. Možno nahradiť metódou add().

addFirst()

Metóda pre vloženie prvku na začiatok fronty.

Queue<int> queue = new Queue();
queue.add(1);
queue.add(2);
queue.add(2);
queue.addFirst(3);
print(queue);

Výstup programu:

Konzolová aplikácia
{3, 1, 2, 2}

removeFirst() a removeLast()

Metódy odstráni prvý / posledný prvok kolekcie a tento prvok vráti.

Queue<int> queue = new Queue();
queue.add(1);
queue.add(2);
queue.add(2);
queue.addFirst(3);
print(queue);
print(queue.removeFirst());
print(queue);
print(queue.removeLast());
print(queue);

Výstup programu:

Konzolová aplikácia
{3, 1, 2, 2}
3
{1, 2, 2}
2
{1, 2}

Map

Mapa, asociatívne pole, slovník, ... Všetky tieto názvy môžete poznať z rôznych programovacích jazykov. V Dart budeme používať pojem mapa. Mapa je kolekcia, ktorá uchováva svoje prvky pod zadanými kľúčmi. V takej kolekcii môžeme k prvkom pristupovať po zadaní kľúča. Rovnako ako u predchádzajúcich kolekcií, prvky môžeme prechádzať v poradí podľa pridania. Dátový typ kľúča zapisujeme do lomených zátvoriek na prvé miesto a na druhej píšeme dátový typ prvku. Ukážme si ukážku:

Map<int, String> mapa = new Map();
mapa[0] = 'nula';
mapa[1] = 'uno';
mapa[2] = 'два';
print(mapa);

Výstup programu:

Konzolová aplikácia
{0: nula, 1: uno, 2: два}

Ako ste si iste všimli už z ukážky, mapa nemá metódu add(). Ak chceme pridať prvok do mapy, zapíšeme kľúč do hranatých zátvoriek a pomocou operátora rovná sa vložíme prvok. Mapa, podobne ako zoznam, možno zapísať pomocou doslovný, pre ktorý sa používajú zložené zátvorky, v ktorých zapisujeme dvojice klíč: prvek oddelené čiarkou. V ukážke si Namapujte postavy zo seriálu Simpsonovci na ich obľúbenú vec, aby sme si ukázali, že mapa nemusí mať na rozdiel od zoznamu číselné kľúče, ale že môžeme indexovať aj reťazci:

Map<int, String> mapa = {
    'Homer': 'kobliha',
    'Marge': 'trouba',
    'Bart': 'prak',
    'Liza': 'kniha',
    'Meggie': 'dudlík',
};

keys a values

Kľúče a prvky mapy sa dajú získať z kolekcií keys a values.

putIfAbsent()

Metóda vhodná pre pridanie prvku iba v prípade, že už taký kľúč neexistuje:

Map<int, String> mapa = {
    0: 'nula',
    1: 'uno',
    2: 'два',
};

mapa.putIfAbsent(2, () => 'dva'); // nepřepíše
print(mapa);
mapa[2] = 'zwei'; // přepíše
print(mapa);

Výstup programu:

Konzolová aplikácia
{0: nula, 1: uno, 2: два}
{0: nula, 1: uno, 2: zwei}

containsKey() a containsValue()

Metódy slúžiace pre určenie, či sa daný kľúč alebo prvok nachádza v kolekcii:

Map<int, String> mapa = {
    0: 'nula',
    1: 'uno',
    2: 'два',
};

print(mapa.containsKey(2));
print(mapa.containsKey(3));

print(mapa.containsValue('uno'));
print(mapa.containsValue('jedna'));

Výstup programu:

Konzolová aplikácia
true
false
true
false

V budúcej lekcii, Diár s databázou v Dart , si naprogramujeme pomocou kolekcií databázu, bude to elektronický diár!:)


 

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é 4x (2.29 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Dart

 

Predchádzajúci článok
Dátum a čas v Dart
Všetky články v sekcii
Objektovo orientované programovanie v Dart
Preskočiť článok
(neodporúčame)
Diár s databázou v Dart
Článok pre vás napísal Honza Bittner
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
FIT ČVUT alumnus :-) Sleduj mě na https://twitter.com/tenhobi a ptej se na cokoli na https://github.com/tenhobi/ama.
Aktivity