diff --git a/priprava/rust_priprava4.md b/priprava/rust_priprava4.md index cfebcc5..a3be1ec 100644 --- a/priprava/rust_priprava4.md +++ b/priprava/rust_priprava4.md @@ -1,261 +1,137 @@ -# Rust — HashMap a HashSet kompletný sprievodca +# HashMap — krok za krokom ---- - -## 1. HashMap — čo to je - -HashMap je kolekcia párov **kľúč → hodnota**. Každý kľúč je unikátny. Vyhľadávanie podľa kľúča je veľmi rýchle (O(1)). - -Predstav si to ako slovník: slovo (kľúč) → definícia (hodnota). +Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej. +Riešenia sú na konci, číslované. ```rust -use std::collections::HashMap; +use std::collections::HashMap; // toto treba vždy ``` -Toto musíš importovať vždy. Nie je v prelude (na rozdiel od Vec alebo String). - --- -## 2. HashMap — vytváranie +## Kapitola 1: Vytvorenie a insert -### Prázdna mapa +HashMap je kolekcia párov kľúč → hodnota. Kľúč je unikátny. ```rust -// Musíš uviesť typy, alebo ich Rust odvodí z prvého insertu let mut mapa: HashMap = HashMap::new(); -// Alebo nechaj Rust odvodiť: -let mut mapa = HashMap::new(); -mapa.insert("Anna".to_string(), 25); // teraz Rust vie: HashMap -``` - -### S kapacitou - -Ak vieš dopredu koľko prvkov budeš mať, môžeš predalokovať: - -```rust -let mut mapa: HashMap = HashMap::with_capacity(100); -``` - -### Z iterátora (collect) - -```rust -// Z vektora dvojíc -let dvojice = vec![("Anna", 25), ("Boris", 30), ("Cyril", 22)]; -let mapa: HashMap<&str, i32> = dvojice.into_iter().collect(); - -// Z dvoch vektorov (zip) -let mena = vec!["Anna", "Boris", "Cyril"]; -let veky = vec![25, 30, 22]; -let mapa: HashMap<&str, i32> = mena.into_iter().zip(veky.into_iter()).collect(); -``` - ---- - -## 3. HashMap — vkladanie (insert) - -```rust -let mut mapa = HashMap::new(); - -// Základný insert — vráti Option (starú hodnotu ak kľúč existoval) -let stara = mapa.insert("Anna".to_string(), 25); -// stara = None (kľúč neexistoval) +mapa.insert("Anna".to_string(), 25); +mapa.insert("Boris".to_string(), 30); +// mapa = {"Anna": 25, "Boris": 30} +// insert na existujúci kľúč PREPÍŠE hodnotu a vráti starú let stara = mapa.insert("Anna".to_string(), 26); -// stara = Some(25) (kľúč existoval, stará hodnota bola 25, teraz je 26) +// stara = Some(25), mapa = {"Anna": 26, "Boris": 30} + +// insert na nový kľúč vráti None +let stara = mapa.insert("Cyril".to_string(), 22); +// stara = None ``` -**Dôležité:** `insert` vždy prepíše hodnotu ak kľúč existuje. Ak chceš vložiť len keď neexistuje, použi `entry` API (sekcia 7). +### Úlohy 1 ---- - -## 4. HashMap — čítanie - -### get — vráti Option<&V> +**1a.** Vytvor HashMap kde kľúče sú mená ovocia (String) a hodnoty sú ceny (f64). Vlož 3 ovocia. +**1b.** Čo vráti posledný insert? Napíš kód a over: ```rust -let mut mapa = HashMap::new(); -mapa.insert("Anna".to_string(), 25); - -// get berie referenciu na kľúč -let vek: Option<&i32> = mapa.get("Anna"); // Some(&25) -let vek: Option<&i32> = mapa.get("Boris"); // None - -// Ak chceš hodnotu rovno: -if let Some(vek) = mapa.get("Anna") { - println!("Anna má {} rokov", vek); -} - -// Alebo s unwrap_or: -let vek = mapa.get("Anna").unwrap_or(&0); // &25 -let vek = mapa.get("Boris").unwrap_or(&0); // &0 +let mut m = HashMap::new(); +m.insert("x", 1); +m.insert("y", 2); +let vysledok = m.insert("x", 99); +println!("{:?}", vysledok); ``` -### get s &String vs &str - +**1c.** Vytvor HashMap z vektora dvojíc pomocou `.collect()`: ```rust -let mut mapa: HashMap = HashMap::new(); -mapa.insert("Anna".to_string(), 25); - -// Obe fungujú — Rust automaticky konvertuje &str na &String pri vyhľadávaní -mapa.get("Anna"); // OK -mapa.get(&"Anna".to_string()); // OK, ale zbytočné -``` - -### Hranatá zátvorka — panické čítanie - -```rust -let vek = mapa["Anna"]; // 25 — ak kľúč neexistuje, PANIC! -// let vek = mapa["Boris"]; // PANIC! program spadne -``` - -**Pravidlo:** Na skúške vždy použi `.get()`, nikdy `[]`. Nechceš panic. - -### get_mut — meniteľná referencia - -```rust -let mut mapa = HashMap::new(); -mapa.insert("Anna".to_string(), 25); - -// Zmeň hodnotu na mieste -if let Some(vek) = mapa.get_mut("Anna") { - *vek += 1; // Anna má teraz 26 -} +let data = vec![("sk", "Slovensko"), ("cz", "Česko"), ("pl", "Poľsko")]; +// tvoj kód → HashMap<&str, &str> ``` --- -## 5. HashMap — kontrola existencie - -```rust -let mapa: HashMap = /* ... */; - -// contains_key — vráti bool -let existuje: bool = mapa.contains_key("Anna"); - -// Dĺžka -let pocet: usize = mapa.len(); - -// Prázdna? -let prazdna: bool = mapa.is_empty(); -``` - ---- - -## 6. HashMap — mazanie +## Kapitola 2: Čítanie — get, contains_key, len ```rust let mut mapa = HashMap::new(); mapa.insert("Anna".to_string(), 25); mapa.insert("Boris".to_string(), 30); -// remove — vráti Option -let odstraneny: Option = mapa.remove("Anna"); -// Some(25) — Anna bola odstránená +// get — vráti Option<&V> +let vek = mapa.get("Anna"); // Some(&25) +let vek = mapa.get("Cyril"); // None -let odstraneny: Option = mapa.remove("Cyril"); -// None — Cyril neexistoval +// contains_key — vráti bool +let je_tam = mapa.contains_key("Anna"); // true +let je_tam = mapa.contains_key("Cyril"); // false -// Vymaž všetko +// len — počet párov +let pocet = mapa.len(); // 2 + +// is_empty +let prazdna = mapa.is_empty(); // false +``` + +**Dôležité:** Nikdy nepoužívaj `mapa["Anna"]` — ak kľúč neexistuje, program spadne. Vždy `.get()`. + +### Úlohy 2 + +**2a.** Máš mapu ovocia z úlohy 1a. Napíš kód, ktorý: +- Vypíše cenu jablka ak existuje +- Vypíše "Nemáme" ak neexistuje +Použi `if let` s `.get()`. + +**2b.** Napíš funkciu: +```rust +fn je_v_mape(mapa: &HashMap, kluc: &str) -> bool +``` +Použi `contains_key`. + +**2c.** Čo vypíše? Tipni, potom over: +```rust +let mut m: HashMap<&str, i32> = HashMap::new(); +m.insert("a", 1); +println!("{:?}", m.get("a")); +println!("{:?}", m.get("b")); +println!("{}", m.len()); +println!("{}", m.contains_key("a")); +println!("{}", m.contains_key("b")); +``` + +--- + +## Kapitola 3: Mazanie — remove, clear + +```rust +let mut mapa = HashMap::new(); +mapa.insert("Anna".to_string(), 25); +mapa.insert("Boris".to_string(), 30); + +// remove — vráti Option (hodnotu, nie referenciu) +let odstraneny = mapa.remove("Anna"); +// odstraneny = Some(25), mapa = {"Boris": 30} + +let odstraneny = mapa.remove("Cyril"); +// odstraneny = None (neexistoval) + +// clear — vymaže všetko mapa.clear(); +// mapa = {} ``` +### Úlohy 3 + +**3a.** Vytvor mapu s 3 položkami. Odstráň jednu. Vypíš čo `remove` vrátil. Vypíš veľkosť mapy. + +**3b.** Napíš funkciu: +```rust +fn odstran_ak_existuje(mapa: &mut HashMap, kluc: &str) -> Option +``` +Ak kľúč existuje, odstráň ho a vráť hodnotu. Ak nie, vráť None. (Hint: `remove` presne toto robí.) + --- -## 7. HashMap — Entry API (NAJDÔLEŽITEJŠIE!) - -Entry API je spôsob, ako efektívne pracovať s kľúčom, ktorý môže alebo nemusí existovať. Toto je na skúške skoro vždy. - -### or_insert — vlož ak neexistuje - -```rust -let mut mapa: HashMap = HashMap::new(); - -// Ak "Anna" neexistuje, vlož 25. Ak existuje, nechaj. -// Vráti &mut na hodnotu (novú alebo existujúcu). -mapa.entry("Anna".to_string()).or_insert(25); -// mapa = {"Anna": 25} - -mapa.entry("Anna".to_string()).or_insert(99); -// mapa = {"Anna": 25} — 99 sa NEVLOŽÍ, lebo Anna už existuje -``` - -### Počítanie výskytov — najčastejší vzor - -```rust -let slova = vec!["ahoj", "svet", "ahoj", "rust", "svet", "ahoj"]; -let mut pocty: HashMap = HashMap::new(); - -for slovo in &slova { - *pocty.entry(slovo.to_string()).or_insert(0) += 1; -} -// pocty = {"ahoj": 3, "svet": 2, "rust": 1} -``` - -Rozklad po krokoch: -``` -1. pocty.entry("ahoj".to_string()) - → kľúč "ahoj" neexistuje → Vacant entry - -2. .or_insert(0) - → vlož 0 → vráť &mut 0 - -3. *(&mut 0) += 1 - → dereferencuj a zvýš → hodnota je teraz 1 - -Druhý prechod "ahoj": -1. pocty.entry("ahoj".to_string()) - → kľúč "ahoj" existuje → Occupied entry - -2. .or_insert(0) - → kľúč existuje, nevkladaj nič → vráť &mut 1 - -3. *(&mut 1) += 1 - → hodnota je teraz 2 -``` - -### or_insert_with — lazy vloženie - -```rust -// or_insert vždy vyhodnotí argument (aj keď ho nevloží) -mapa.entry(kluc).or_insert(drahy_vypocet()); // drahy_vypocet() sa zavolá VŽDY - -// or_insert_with zavolá closure LEN ak kľúč neexistuje -mapa.entry(kluc).or_insert_with(|| drahy_vypocet()); // zavolá sa len ak treba -``` - -### or_default — použi Default trait - -```rust -// Pre usize → 0, pre String → "", pre Vec → vec![], pre bool → false -let mut pocty: HashMap = HashMap::new(); -*pocty.entry("ahoj".to_string()).or_default() += 1; -// or_default() je to isté ako or_insert(0) pre usize - -// Zoskupovanie do vektorov: -let mut skupiny: HashMap> = HashMap::new(); -skupiny.entry("ovocie".to_string()).or_default().push("jablko".to_string()); -skupiny.entry("ovocie".to_string()).or_default().push("hruška".to_string()); -skupiny.entry("zelenina".to_string()).or_default().push("mrkva".to_string()); -// skupiny = {"ovocie": ["jablko", "hruška"], "zelenina": ["mrkva"]} -``` - -### and_modify — uprav existujúcu hodnotu - -```rust -let mut mapa: HashMap = HashMap::new(); - -// Ak existuje, zvýš o 1. Ak neexistuje, vlož 1. -mapa.entry("Anna".to_string()) - .and_modify(|v| *v += 1) - .or_insert(1); -``` - -Toto je alternatíva k vzoru `*entry.or_insert(0) += 1`, ale je explicitnejšie keď modifikácia a vloženie robia rôzne veci. - ---- - -## 8. HashMap — iterácia +## Kapitola 4: Iterácia ```rust let mut mapa = HashMap::new(); @@ -263,7 +139,7 @@ mapa.insert("Anna".to_string(), 25); mapa.insert("Boris".to_string(), 30); mapa.insert("Cyril".to_string(), 22); -// Iterácia cez páry (kľúč, hodnota) — poradie NIE JE garantované! +// Cez páry — poradie NIE JE garantované! for (meno, vek) in &mapa { println!("{}: {}", meno, vek); } @@ -278,476 +154,310 @@ for vek in mapa.values() { println!("{}", vek); } -// Meniteľná iterácia cez hodnoty +// Meniteľné hodnoty for vek in mapa.values_mut() { - *vek += 1; // všetkým pridaj rok + *vek += 1; +} +``` + +### Úlohy 4 + +**4a.** Vytvor mapu produktov (názov → cena). Vypíš všetky produkty vo formáte `"Produkt: cena €"`. + +**4b.** Napíš funkciu, ktorá vráti vektor všetkých kľúčov z mapy: +```rust +fn kluce(mapa: &HashMap) -> Vec<&String> +``` + +**4c.** Napíš funkciu, ktorá zvýši všetky hodnoty v mape o 10: +```rust +fn zvys_vsetky(mapa: &mut HashMap) +``` + +**4d.** Napíš funkciu, ktorá vráti súčet všetkých hodnôt: +```rust +fn sucet_hodnot(mapa: &HashMap) -> i32 +``` +Použi `.values()` a `.sum()`. + +--- + +## Kapitola 5: get_mut — zmena hodnoty na mieste + +Ak chceš zmeniť jednu konkrétnu hodnotu (nie všetky), použi `get_mut`: + +```rust +let mut mapa = HashMap::new(); +mapa.insert("Anna".to_string(), 25); + +// get_mut vráti Option<&mut V> +if let Some(vek) = mapa.get_mut("Anna") { + *vek += 1; // Anna má teraz 26 } -// Iterátor + collect — napr. kľúče do Vec +// Ak kľúč neexistuje, get_mut vráti None +if let Some(vek) = mapa.get_mut("Boris") { + *vek += 1; // Toto sa nevykoná +} +``` + +### Úlohy 5 + +**5a.** Máš mapu študentov (meno → počet bodov). Napíš funkciu, ktorá pridá body jednému študentovi: +```rust +fn pridaj_body(mapa: &mut HashMap, meno: &str, body: u32) -> bool +``` +Vráti `true` ak študent existoval, `false` ak nie. + +**5b.** Napíš funkciu, ktorá zdvojnásobí hodnotu pre daný kľúč: +```rust +fn zdvojnasob(mapa: &mut HashMap, kluc: &str) -> Option +``` +Vráti novú hodnotu ak kľúč existoval, None ak nie. + +--- + +## Kapitola 6: Entry API — or_insert + +Toto je najdôležitejšia časť. Entry API rieši situáciu: "ak kľúč neexistuje, vlož default; ak existuje, použi existujúcu hodnotu." + +```rust +let mut mapa: HashMap = HashMap::new(); + +// entry() vráti Entry — buď Vacant (prázdny) alebo Occupied (obsadený) +// or_insert(hodnota) — ak Vacant, vlož hodnotu. Vráti &mut na hodnotu. + +mapa.entry("Anna".to_string()).or_insert(25); +// Anna neexistovala → vloží 25 → mapa = {"Anna": 25} + +mapa.entry("Anna".to_string()).or_insert(99); +// Anna existuje → NEVLOŽÍ 99 → mapa = {"Anna": 25} (nezmenené!) +``` + +**Hlavné použitie — počítanie výskytov:** + +```rust +let slova = vec!["ahoj", "svet", "ahoj", "rust", "svet", "ahoj"]; +let mut pocty: HashMap = HashMap::new(); + +for slovo in &slova { + *pocty.entry(slovo.to_string()).or_insert(0) += 1; +} +// {"ahoj": 3, "svet": 2, "rust": 1} +``` + +Čo sa deje krok po kroku: +``` +Slovo "ahoj": + entry("ahoj") → Vacant → or_insert(0) vloží 0 → vráti &mut 0 + *(&mut 0) += 1 → hodnota je 1 + +Slovo "svet": + entry("svet") → Vacant → or_insert(0) vloží 0 → vráti &mut 0 + *(&mut 0) += 1 → hodnota je 1 + +Slovo "ahoj" (druhýkrát): + entry("ahoj") → Occupied (hodnota 1) → or_insert(0) NEVLOŽÍ → vráti &mut 1 + *(&mut 1) += 1 → hodnota je 2 +``` + +### Úlohy 6 + +**6a.** Spočítaj výskyt každého znaku v reťazci `"abrakadabra"`. Použi `entry` + `or_insert`. Výsledok vypíš. + +**6b.** Máš vektor čísel `[1, 3, 2, 1, 4, 3, 2, 1, 5]`. Spočítaj koľkokrát sa vyskytuje každé číslo. + +**6c.** Čo vypíše? Tipni, potom over: +```rust +let mut m: HashMap<&str, i32> = HashMap::new(); +m.entry("a").or_insert(10); +m.entry("b").or_insert(20); +m.entry("a").or_insert(99); +m.insert("b", 99); +println!("{:?}", m.get("a")); +println!("{:?}", m.get("b")); +``` + +--- + +## Kapitola 7: Entry API — or_default + +`or_default()` je skratka za `or_insert(Default::default())`. Vloží defaultnú hodnotu pre daný typ. + +| Typ | Default | +|-----|---------| +| usize, i32, u32... | 0 | +| f64 | 0.0 | +| bool | false | +| String | "" | +| Vec | vec![] | + +```rust +let mut pocty: HashMap = HashMap::new(); + +// Tieto dva riadky robia to isté: +*pocty.entry("ahoj".to_string()).or_insert(0) += 1; +*pocty.entry("ahoj".to_string()).or_default() += 1; +``` + +**Hlavné použitie — zoskupovanie do vektorov:** + +```rust +let mut skupiny: HashMap> = HashMap::new(); + +// or_default() pre Vec vloží prázdny vektor +skupiny.entry("ovocie".to_string()).or_default().push("jablko".to_string()); +skupiny.entry("ovocie".to_string()).or_default().push("hruška".to_string()); +skupiny.entry("zelenina".to_string()).or_default().push("mrkva".to_string()); +// {"ovocie": ["jablko", "hruška"], "zelenina": ["mrkva"]} +``` + +### Úlohy 7 + +**7a.** Máš vektor slov. Zoskup ich podľa prvého písmena do HashMap>: +```rust +let slova = vec!["auto", "ahoj", "banán", "breza", "citrón", "auto"]; +// Výsledok: {'a': ["auto", "ahoj", "auto"], 'b': ["banán", "breza"], 'c': ["citrón"]} +``` + +**7b.** Máš vektor dvojíc (študent, predmet). Zoskup predmety podľa študenta: +```rust +let data = vec![ + ("Anna", "Matematika"), + ("Boris", "Fyzika"), + ("Anna", "Fyzika"), + ("Boris", "Chémia"), + ("Anna", "Chémia"), +]; +// Výsledok: {"Anna": ["Matematika", "Fyzika", "Chémia"], "Boris": ["Fyzika", "Chémia"]} +``` + +--- + +## Kapitola 8: Entry API — and_modify + +`and_modify` ti umožní spraviť niečo s existujúcou hodnotou pred tým, ako sa rozhodne čo robiť: + +```rust +let mut mapa: HashMap = HashMap::new(); + +// Ak existuje → zvýš o 1. Ak neexistuje → vlož 1. +mapa.entry("Anna".to_string()) + .and_modify(|v| *v += 1) + .or_insert(1); +// Anna neexistovala → vloží 1 + +mapa.entry("Anna".to_string()) + .and_modify(|v| *v += 1) + .or_insert(1); +// Anna existuje s hodnotou 1 → and_modify zvýši na 2 +``` + +Toto je užitočné keď chceš robiť rôzne veci pre nový vs existujúci kľúč. + +### Úlohy 8 + +**8a.** Máš vektor mien. Pre každé meno: ak sa vyskytlo prvýkrát, vlož `1`. Ak sa vyskytlo znovu, zvýš o `1`. Použi `and_modify` + `or_insert`. (Áno, výsledok je rovnaký ako cez `or_insert(0) += 1`, ale precvič si syntax.) + +**8b.** Máš mapu produktov (String → (cena: f64, počet: u32)). Napíš kód, ktorý: ak produkt existuje, zvýši počet o 1. Ak neexistuje, vloží ho s cenou 10.0 a počtom 1. +```rust +let mut produkty: HashMap = HashMap::new(); +// tvoj kód pre produkt "mlieko" +``` + +--- + +## Kapitola 9: Iterátory s HashMap + +HashMap sa dá kombinovať s iterátorovými metódami: + +```rust +let mut mapa = HashMap::new(); +mapa.insert("Anna".to_string(), 25); +mapa.insert("Boris".to_string(), 30); +mapa.insert("Cyril".to_string(), 17); + +// filter — nechaj len dospelých +let dospeli: HashMap<&String, &i32> = mapa.iter() + .filter(|(_, vek)| **vek >= 18) + .collect(); + +// find — nájdi prvého s daným menom +let boris: Option<(&String, &i32)> = mapa.iter() + .find(|(meno, _)| meno.as_str() == "Boris"); + +// max_by_key — najstarší +let najstarsi: Option<(&String, &i32)> = mapa.iter() + .max_by_key(|(_, vek)| *vek); + +// Kľúče do Vec let mena: Vec<&String> = mapa.keys().collect(); -// Iterátor + filter -let stari: Vec<(&String, &i32)> = mapa.iter().filter(|(_, vek)| **vek > 25).collect(); +// Hodnoty — súčet +let sucet_vekov: i32 = mapa.values().sum(); ``` -**Dôležité:** HashMap negarantuje poradie! Ak chceš zoradené, musíš po iterácii triediť alebo použiť BTreeMap. +### Úlohy 9 + +**9a.** Máš `HashMap` (produkt → cena). Nájdi najdrahší produkt. Vráť jeho názov ako `Option<&String>`. + +**9b.** Máš `HashMap` (mesto → populácia). Vráť Vec miest s populáciou nad 100_000. + +**9c.** Máš `HashMap>` (kategória → produkty). Nájdi celkový počet produktov naprieč všetkými kategóriami. Použi `.values()` a `.map()` a `.sum()`. --- -## 9. HashMap — praktické vzory zo skúšky +## Kapitola 10: Praktické vzory zo skúšky -### Vzor 1: Počítanie podľa kategórie +### Vzor 1: Počítanie podľa poľa štruktúry ```rust -struct Kniha { nazov: String, zaner: String } +struct Kniha { nazov: String, vydavatelstvo: String } -fn pocty_zanrov(knihy: &[Kniha]) -> HashMap { +fn pocty_podla_vydavatelstva(knihy: &[Kniha]) -> HashMap { let mut mapa = HashMap::new(); for kniha in knihy { - *mapa.entry(kniha.zaner.clone()).or_insert(0) += 1; + *mapa.entry(kniha.vydavatelstvo.clone()).or_insert(0) += 1; } mapa } ``` -### Vzor 2: Výpis štatistík +### Vzor 2: Výpis vo formáte "Kľúč: hodnota" ```rust -fn vypis_vydavatelstva_a_pocet(knihy: &[Kniha]) { - let pocty = pocty_zanrov(knihy); - for (zaner, pocet) in &pocty { - println!("{}: {}", zaner, pocet); +fn vypis_statistiky(knihy: &[Kniha]) { + let pocty = pocty_podla_vydavatelstva(knihy); + for (vydavatelstvo, pocet) in &pocty { + println!("{}: {}", vydavatelstvo, pocet); } } ``` -### Vzor 3: Zoskupenie do vektorov +### Vzor 3: Nájdi najčastejší ```rust -fn knihy_podla_zanru<'a>(knihy: &'a [Kniha]) -> HashMap> { - let mut mapa: HashMap> = HashMap::new(); - for kniha in knihy { - mapa.entry(kniha.zaner.clone()).or_default().push(kniha); - } - mapa -} -``` - -### Vzor 4: Najdi najčastejší - -```rust -fn najcastejsi_zaner(knihy: &[Kniha]) -> Option { - let pocty = pocty_zanrov(knihy); +fn najcastejsie_vydavatelstvo(knihy: &[Kniha]) -> Option { + let pocty = pocty_podla_vydavatelstva(knihy); pocty.into_iter() .max_by_key(|(_, pocet)| *pocet) - .map(|(zaner, _)| zaner) + .map(|(vydavatelstvo, _)| vydavatelstvo) } ``` ---- +### Úlohy 10 -## 10. HashMap — Úloha na precvičenie - -**Úloha HM-1:** Napíš funkciu `pocitaj_slova(text: &str) -> HashMap` ktorá rozdelí text na slová (`.split_whitespace()`) a spočíta výskyt každého slova. Preveď slová na lowercase (`.to_lowercase()`). - -**Úloha HM-2:** Máš: +**10a.** Máš: ```rust -struct Objednavka { zakaznik: String, suma: f64, mesto: String } +struct Zamestnanec { meno: String, oddelenie: String, plat: u32 } ``` -Napíš: -- a) `pocet_objednavok_podla_mesta(objednavky: &[Objednavka]) -> HashMap` -- b) `celkova_suma_podla_zakaznika(objednavky: &[Objednavka]) -> HashMap` -- c) `objednavky_podla_mesta(objednavky: &[Objednavka]) -> HashMap>` -- d) `mesto_s_najviac_objednavkami(objednavky: &[Objednavka]) -> Option` -- e) `najlepsi_zakaznik(objednavky: &[Objednavka]) -> Option` — zákazník s najvyššou celkovou sumou +Napíš funkciu `pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap`. -**Úloha HM-3:** Napíš funkciu `invertuj(mapa: &HashMap>) -> HashMap>`. Vstup: kategórie → položky. Výstup: položka → kategórie. Príklad: -``` -Vstup: {"ovocie": ["jablko", "hruška"], "červené": ["jablko", "jahoda"]} -Výstup: {"jablko": ["ovocie", "červené"], "hruška": ["ovocie"], "jahoda": ["červené"]} -``` +**10b.** Napíš funkciu `celkovy_plat_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap` — súčet platov na každom oddelení. -**Úloha HM-4:** Napíš funkciu `najcastejsi_znak(text: &str) -> Option` — vráti najčastejší znak v texte (ignoruj medzery). Ak je text prázdny, vráť None. +**10c.** Napíš funkciu `vypis_statistiky(zamestnanci: &[Zamestnanec])` — pre každé oddelenie vypíše počet ľudí a celkový plat. ---- - ---- - -## 11. HashSet — čo to je - -HashSet je kolekcia **unikátnych hodnôt**. Žiadna hodnota sa nemôže opakovať. Je to vlastne HashMap kde ťa zaujímajú len kľúče, nie hodnoty. - -Predstav si to ako množinu v matematike: {1, 2, 3}. - -```rust -use std::collections::HashSet; -``` - ---- - -## 12. HashSet — vytváranie - -### Prázdna množina - -```rust -let mut mnozina: HashSet = HashSet::new(); - -// Alebo nechaj odvodiť: -let mut mnozina = HashSet::new(); -mnozina.insert("Anna".to_string()); // teraz Rust vie: HashSet -``` - -### Z iterátora (collect) - -```rust -let cisla = vec![1, 2, 3, 2, 1, 4, 3, 5]; -let unikatne: HashSet = cisla.into_iter().collect(); -// {1, 2, 3, 4, 5} — duplikáty zmizli - -// Z reťazca — množina znakov -let znaky: HashSet = "abrakadabra".chars().collect(); -// {'a', 'b', 'r', 'k', 'd'} -``` - -### S kapacitou - -```rust -let mut mnozina: HashSet = HashSet::with_capacity(100); -``` - ---- - -## 13. HashSet — vkladanie (insert) - -```rust -let mut mnozina = HashSet::new(); - -// insert vráti bool — true ak sa vložilo (prvok neexistoval), false ak už existoval -let nova: bool = mnozina.insert("Anna".to_string()); -// true — Anna bola pridaná - -let nova: bool = mnozina.insert("Anna".to_string()); -// false — Anna už existuje, nič sa nezmenilo -``` - -Toto je užitočné na kontrolu duplikátov: -```rust -if !mnozina.insert(hodnota) { - println!("Duplikát!"); -} -``` - ---- - -## 14. HashSet — kontrola existencie (contains) - -```rust -let mut mnozina = HashSet::new(); -mnozina.insert("Anna".to_string()); -mnozina.insert("Boris".to_string()); - -let existuje: bool = mnozina.contains("Anna"); // true -let existuje: bool = mnozina.contains("Cyril"); // false - -// Dĺžka -let pocet: usize = mnozina.len(); // 2 - -// Prázdna? -let prazdna: bool = mnozina.is_empty(); // false -``` - -**contains s &str vs &String:** Rovnako ako HashMap — `contains("Anna")` funguje aj keď máš `HashSet`. - ---- - -## 15. HashSet — mazanie - -```rust -let mut mnozina = HashSet::new(); -mnozina.insert(1); -mnozina.insert(2); -mnozina.insert(3); - -// remove — vráti bool (true ak existoval) -let bol_tam: bool = mnozina.remove(&2); // true, mnozina = {1, 3} -let bol_tam: bool = mnozina.remove(&5); // false, nič sa nezmenilo - -// Vymaž všetko -mnozina.clear(); -``` - ---- - -## 16. HashSet — iterácia - -```rust -let mnozina: HashSet = vec![1, 2, 3, 4, 5].into_iter().collect(); - -// Iterácia — poradie NIE JE garantované! -for prvok in &mnozina { - println!("{}", prvok); -} - -// Iterátor + filter + collect -let parne: HashSet<&i32> = mnozina.iter().filter(|c| *c % 2 == 0).collect(); - -// Do Vec -let vektor: Vec<&i32> = mnozina.iter().collect(); - -// Počet prvkov spĺňajúcich podmienku -let pocet_parnych: usize = mnozina.iter().filter(|c| *c % 2 == 0).count(); -``` - ---- - -## 17. HashSet — množinové operácie - -Toto je to, čo robí HashSet špeciálnym oproti Vec. Tieto operácie sú veľmi efektívne. - -### Prienik (intersection) — prvky v oboch - -```rust -let a: HashSet = vec![1, 2, 3, 4].into_iter().collect(); -let b: HashSet = vec![3, 4, 5, 6].into_iter().collect(); - -// intersection vráti iterátor -let prienik: HashSet<&i32> = a.intersection(&b).collect(); -// {&3, &4} - -// Alebo do Vec -let prienik: Vec<&i32> = a.intersection(&b).collect(); -``` - -### Zjednotenie (union) — prvky v aspoň jednom - -```rust -let zjednotenie: HashSet<&i32> = a.union(&b).collect(); -// {&1, &2, &3, &4, &5, &6} -``` - -### Rozdiel (difference) — prvky v A, ktoré nie sú v B - -```rust -let rozdiel: HashSet<&i32> = a.difference(&b).collect(); -// {&1, &2} - -// Opačný smer: -let rozdiel_opacny: HashSet<&i32> = b.difference(&a).collect(); -// {&5, &6} -``` - -### Symetrický rozdiel — prvky v jednom, ale nie v oboch - -```rust -let sym_rozdiel: HashSet<&i32> = a.symmetric_difference(&b).collect(); -// {&1, &2, &5, &6} -``` - -### Podmnožina a nadmnožina - -```rust -let mala: HashSet = vec![1, 2].into_iter().collect(); -let velka: HashSet = vec![1, 2, 3, 4].into_iter().collect(); - -let je_podmnozina: bool = mala.is_subset(&velka); // true -let je_nadmnozina: bool = velka.is_superset(&mala); // true -let je_disjunktna: bool = mala.is_disjoint(&velka); // false (majú spoločné prvky) -``` - -### Operátory - -```rust -// Tieto operátory fungujú tiež: -let prienik = &a & &b; // intersection -let zjednotenie = &a | &b; // union -let rozdiel = &a - &b; // difference -let sym_rozdiel = &a ^ &b; // symmetric_difference -// Vracajú nový HashSet (nie referencie) -``` - ---- - -## 18. HashSet — praktické použitie v Ruste - -### Vzor 1: Sledovanie už videných hodnôt - -```rust -fn ma_duplikaty(cisla: &[i32]) -> bool { - let mut videne = HashSet::new(); - for c in cisla { - if !videne.insert(c) { - return true; // insert vrátil false → duplikát - } - } - false -} -``` - -### Vzor 2: Unikátne hodnoty z kolekcie - -```rust -fn unikatne_zanre(knihy: &[Kniha]) -> Vec { - let mnozina: HashSet = knihy.iter().map(|k| k.zaner.clone()).collect(); - mnozina.into_iter().collect() -} -``` - -### Vzor 3: Rýchle vyhľadávanie (namiesto Vec.contains) - -```rust -// Vec.contains je pomalé (O(n)) — prechádza celý vektor -let povolene_vec = vec!["admin", "editor", "viewer"]; -povolene_vec.contains(&"admin"); // O(n) - -// HashSet.contains je rýchle (O(1)) -let povolene_set: HashSet<&str> = vec!["admin", "editor", "viewer"].into_iter().collect(); -povolene_set.contains("admin"); // O(1) -``` - -Ak kontroluješ existenciu opakovane (napr. v cykle), vždy použi HashSet. - -### Vzor 4: Obesenec — uhádnuté písmená (zo skúšky!) - -```rust -struct Hra { - hladane_slovo: String, - uhadnute_pismena: HashSet, - skusane_pismena: HashSet, - pocet_zivotov: u8, -} - -impl Hra { - fn new(slovo: &str) -> Hra { - Hra { - hladane_slovo: slovo.to_lowercase(), - uhadnute_pismena: HashSet::new(), - skusane_pismena: HashSet::new(), - pocet_zivotov: 6, - } - } - - fn tipni(&mut self, pismeno: char) { - let p = pismeno.to_lowercase().next().unwrap(); - - // Ak sme už skúšali toto písmeno — preskočíme - if !self.skusane_pismena.insert(p) { - println!("Toto písmeno si už skúšal!"); - return; - } - - // Je písmeno v slove? - if self.hladane_slovo.contains(p) { - self.uhadnute_pismena.insert(p); - println!("Správne!"); - } else { - self.pocet_zivotov -= 1; - println!("Zle! Zostáva životov: {}", self.pocet_zivotov); - } - } - - fn zobraz_slovo(&self) -> String { - self.hladane_slovo.chars().map(|c| { - if self.uhadnute_pismena.contains(&c) { c } else { '_' } - }).collect() - } - - fn je_vyhra(&self) -> bool { - self.hladane_slovo.chars().all(|c| self.uhadnute_pismena.contains(&c)) - } -} -``` - ---- - -## 19. HashSet — kedy HashSet, kedy Vec - -| Situácia | Použi | -|----------|-------| -| Potrebuješ poradie prvkov | Vec | -| Potrebuješ duplikáty | Vec | -| Potrebuješ index (prvý, druhý, ...) | Vec | -| Často kontroluješ `contains` | HashSet | -| Potrebuješ unikátne hodnoty | HashSet | -| Robíš množinové operácie (prienik, ...) | HashSet | -| Sleduješ "už som videl" | HashSet | -| Chceš rýchle pridávanie + kontrolu | HashSet | - ---- - -## 20. HashMap vs HashSet - -| | HashMap | HashSet | -|-|---------|---------| -| Ukladá | kľúč → hodnota | len hodnota | -| Import | `use std::collections::HashMap` | `use std::collections::HashSet` | -| Vloženie | `.insert(kľúč, hodnota)` → `Option` | `.insert(hodnota)` → `bool` | -| Vyhľadanie | `.get(&kľúč)` → `Option<&V>` | `.contains(&hodnota)` → `bool` | -| Mazanie | `.remove(&kľúč)` → `Option` | `.remove(&hodnota)` → `bool` | -| Entry API | áno | nie (nepotrebné) | -| Množinové operácie | nie | áno (intersection, union, ...) | - -HashSet je vnútorne implementovaný ako `HashMap` — teda HashMap kde hodnota je prázdna. - ---- - -## 21. HashSet — Úloha na precvičenie - -**Úloha HS-1:** Napíš funkciu `unikatne_znaky(text: &str) -> HashSet` — vráti množinu všetkých unikátnych znakov v texte (bez medzier). - -**Úloha HS-2:** Napíš funkciu `spolocne_znaky(text1: &str, text2: &str) -> HashSet` — vráti znaky, ktoré sa vyskytujú v oboch textoch. - -**Úloha HS-3:** Napíš funkciu `ma_duplikaty(cisla: &[i32]) -> bool` — vráti true ak vektor obsahuje duplikáty. Použi HashSet. - -**Úloha HS-4:** Napíš funkciu `unikatne_slova(text: &str) -> usize` — vráti počet unikátnych slov v texte (case-insensitive, použi `.to_lowercase()`). - -**Úloha HS-5:** Máš dva vektory mien. Napíš: -- a) `spolocni(a: &[String], b: &[String]) -> Vec` — mená v oboch -- b) `len_v_prvom(a: &[String], b: &[String]) -> Vec` — mená len v prvom - -**Úloha HS-6:** Implementuj štruktúru `Slovnik` pre obesenca: -```rust -struct Slovnik { - slova: HashMap>, // kategória → slová -} -``` -Napíš: -- a) `new() -> Slovnik` -- b) `pridaj_kategoriu(&mut self, kategoria: &str)` — pridá prázdnu kategóriu ak neexistuje -- c) `pridaj_slovo(&mut self, kategoria: &str, slovo: &str) -> Result<(), ()>` — Err ak kategória neexistuje -- d) `nahodne_slovo(&self, kategoria: &str) -> Option<&String>` — náhodné slovo z kategórie (použi `rand`) -- e) `vsetky_kategorie(&self) -> Vec<&String>` — zoznam kategórií -- f) `pocet_slov_v_kategorii(&self, kategoria: &str) -> Option` — None ak kategória neexistuje - ---- - -## 22. Kombinovaná úloha — HashMap + HashSet spolu - -**Úloha K-1:** Máš: -```rust -struct Student { - meno: String, - predmety: HashSet, - znamky: HashMap, // predmet → známka -} -``` -Napíš: -- a) `fn pridaj_predmet(&mut self, predmet: &str)` — pridá predmet do množiny -- b) `fn zadaj_znamku(&mut self, predmet: &str, znamka: u8) -> Result<(), ()>` — Err ak študent nemá predmet -- c) `fn priemer(&self) -> Option` — priemer známok, None ak žiadne -- d) `fn spolocne_predmety(s1: &Student, s2: &Student) -> HashSet` — predmety oboch -- e) `fn ma_vsetky_znamky(&self) -> bool` — má známku z každého predmetu? - -**Úloha K-2:** Máš: -```rust -struct Skola { - studenti: Vec, -} -``` -Napíš: -- a) `fn vsetky_predmety(&self) -> HashSet` — všetky predmety naprieč všetkými študentmi -- b) `fn studenti_s_predmetom(&self, predmet: &str) -> Vec<&Student>` — študenti zapísaní na predmet -- c) `fn priemer_za_predmet(&self, predmet: &str) -> Option` — priemer známok za predmet naprieč študentmi -- d) `fn najlepsi_student(&self) -> Option<&Student>` — študent s najnižším priemerom (kto má znamky) +**10d.** Napíš funkciu `oddelenie_s_najvyssim_platom(zamestnanci: &[Zamestnanec]) -> Option` — oddelenie kde je najväčší celkový plat. --- @@ -757,309 +467,296 @@ Napíš: # RIEŠENIA -## HM-1 +## 1a ```rust -fn pocitaj_slova(text: &str) -> HashMap { - let mut mapa = HashMap::new(); - for slovo in text.split_whitespace() { - *mapa.entry(slovo.to_lowercase()).or_insert(0) += 1; - } - mapa +let mut ovocie: HashMap = HashMap::new(); +ovocie.insert("Jablko".to_string(), 1.50); +ovocie.insert("Banán".to_string(), 2.00); +ovocie.insert("Pomaranč".to_string(), 2.50); +``` + +## 1b + +``` +Some(1) +``` +Lebo `"x"` už existoval s hodnotou 1, `insert` ho prepísal na 99 a vrátil starú hodnotu. + +## 1c + +```rust +let data = vec![("sk", "Slovensko"), ("cz", "Česko"), ("pl", "Poľsko")]; +let mapa: HashMap<&str, &str> = data.into_iter().collect(); +``` + +## 2a + +```rust +if let Some(cena) = ovocie.get("Jablko") { + println!("Cena: {} €", cena); +} else { + println!("Nemáme"); } ``` -## HM-2 +## 2b ```rust -struct Objednavka { zakaznik: String, suma: f64, mesto: String } +fn je_v_mape(mapa: &HashMap, kluc: &str) -> bool { + mapa.contains_key(kluc) +} +``` -// a) -fn pocet_objednavok_podla_mesta(objednavky: &[Objednavka]) -> HashMap { - let mut mapa = HashMap::new(); - for obj in objednavky { - *mapa.entry(obj.mesto.clone()).or_insert(0) += 1; +## 2c + +``` +Some(1) +None +1 +true +false +``` + +## 3a + +```rust +let mut mapa = HashMap::new(); +mapa.insert("A".to_string(), 1); +mapa.insert("B".to_string(), 2); +mapa.insert("C".to_string(), 3); + +let odstraneny = mapa.remove("B"); +println!("{:?}", odstraneny); // Some(2) +println!("{}", mapa.len()); // 2 +``` + +## 3b + +```rust +fn odstran_ak_existuje(mapa: &mut HashMap, kluc: &str) -> Option { + mapa.remove(kluc) +} +``` + +## 4a + +```rust +let mut produkty = HashMap::new(); +produkty.insert("Chlieb".to_string(), 1.20); +produkty.insert("Mlieko".to_string(), 0.89); +produkty.insert("Maslo".to_string(), 2.50); + +for (nazov, cena) in &produkty { + println!("{}: {} €", nazov, cena); +} +``` + +## 4b + +```rust +fn kluce(mapa: &HashMap) -> Vec<&String> { + mapa.keys().collect() +} +``` + +## 4c + +```rust +fn zvys_vsetky(mapa: &mut HashMap) { + for hodnota in mapa.values_mut() { + *hodnota += 10; } - mapa } +``` -// b) -fn celkova_suma_podla_zakaznika(objednavky: &[Objednavka]) -> HashMap { - let mut mapa: HashMap = HashMap::new(); - for obj in objednavky { - *mapa.entry(obj.zakaznik.clone()).or_insert(0.0) += obj.suma; +## 4d + +```rust +fn sucet_hodnot(mapa: &HashMap) -> i32 { + mapa.values().sum() +} +``` + +## 5a + +```rust +fn pridaj_body(mapa: &mut HashMap, meno: &str, body: u32) -> bool { + if let Some(aktualne) = mapa.get_mut(meno) { + *aktualne += body; + true + } else { + false } - mapa } +``` -// c) -fn objednavky_podla_mesta<'a>(objednavky: &'a [Objednavka]) -> HashMap> { - let mut mapa: HashMap> = HashMap::new(); - for obj in objednavky { - mapa.entry(obj.mesto.clone()).or_default().push(obj); +## 5b + +```rust +fn zdvojnasob(mapa: &mut HashMap, kluc: &str) -> Option { + let hodnota = mapa.get_mut(kluc)?; + *hodnota *= 2; + Some(*hodnota) +} +``` + +## 6a + +```rust +let text = "abrakadabra"; +let mut pocty: HashMap = HashMap::new(); +for c in text.chars() { + *pocty.entry(c).or_insert(0) += 1; +} +for (znak, pocet) in &pocty { + println!("{}: {}", znak, pocet); +} +``` + +## 6b + +```rust +let cisla = vec![1, 3, 2, 1, 4, 3, 2, 1, 5]; +let mut pocty: HashMap = HashMap::new(); +for c in &cisla { + *pocty.entry(*c).or_insert(0) += 1; +} +// {1: 3, 3: 2, 2: 2, 4: 1, 5: 1} +``` + +## 6c + +``` +Some(10) +Some(99) +``` +`entry("a").or_insert(99)` — "a" už existuje, takže 99 sa NEVLOŽÍ, ostáva 10. +`insert("b", 99)` — insert VŽDY prepíše, takže "b" je teraz 99. + +## 7a + +```rust +let slova = vec!["auto", "ahoj", "banán", "breza", "citrón", "auto"]; +let mut skupiny: HashMap> = HashMap::new(); +for slovo in &slova { + if let Some(prvy) = slovo.chars().next() { + skupiny.entry(prvy).or_default().push(slovo.to_string()); } - mapa } +``` -// d) -fn mesto_s_najviac_objednavkami(objednavky: &[Objednavka]) -> Option { - let pocty = pocet_objednavok_podla_mesta(objednavky); - pocty.into_iter() - .max_by_key(|(_, pocet)| *pocet) - .map(|(mesto, _)| mesto) +## 7b + +```rust +let data = vec![ + ("Anna", "Matematika"), + ("Boris", "Fyzika"), + ("Anna", "Fyzika"), + ("Boris", "Chémia"), + ("Anna", "Chémia"), +]; +let mut mapa: HashMap> = HashMap::new(); +for (student, predmet) in &data { + mapa.entry(student.to_string()).or_default().push(predmet.to_string()); } +``` -// e) -fn najlepsi_zakaznik(objednavky: &[Objednavka]) -> Option { - let sumy = celkova_suma_podla_zakaznika(objednavky); - sumy.into_iter() +## 8a + +```rust +let mena = vec!["Anna", "Boris", "Anna", "Cyril", "Boris", "Anna"]; +let mut pocty: HashMap = HashMap::new(); +for meno in &mena { + pocty.entry(meno.to_string()) + .and_modify(|v| *v += 1) + .or_insert(1); +} +// {"Anna": 3, "Boris": 2, "Cyril": 1} +``` + +## 8b + +```rust +let mut produkty: HashMap = HashMap::new(); +produkty.entry("mlieko".to_string()) + .and_modify(|(_, pocet)| *pocet += 1) + .or_insert((10.0, 1)); +``` + +## 9a + +```rust +fn najdrahsi(mapa: &HashMap) -> Option<&String> { + mapa.iter() .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap()) - .map(|(zakaznik, _)| zakaznik) + .map(|(nazov, _)| nazov) } ``` -## HM-3 +## 9b ```rust -fn invertuj(mapa: &HashMap>) -> HashMap> { - let mut nova: HashMap> = HashMap::new(); - for (kategoria, polozky) in mapa { - for polozka in polozky { - nova.entry(polozka.clone()).or_default().push(kategoria.clone()); - } - } - nova +fn velke_mesta(mapa: &HashMap) -> Vec<&String> { + mapa.iter() + .filter(|(_, pop)| **pop > 100_000) + .map(|(mesto, _)| mesto) + .collect() } ``` -## HM-4 +## 9c ```rust -fn najcastejsi_znak(text: &str) -> Option { - let mut pocty: HashMap = HashMap::new(); - for c in text.chars() { - if c != ' ' { - *pocty.entry(c).or_insert(0) += 1; - } - } - pocty.into_iter() - .max_by_key(|(_, pocet)| *pocet) - .map(|(znak, _)| znak) +fn celkovy_pocet(mapa: &HashMap>) -> usize { + mapa.values().map(|v| v.len()).sum() } ``` -## HS-1 +## 10a ```rust -fn unikatne_znaky(text: &str) -> HashSet { - text.chars().filter(|c| *c != ' ').collect() +fn pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap { + let mut mapa = HashMap::new(); + for z in zamestnanci { + *mapa.entry(z.oddelenie.clone()).or_insert(0) += 1; + } + mapa } ``` -## HS-2 +## 10b ```rust -fn spolocne_znaky(text1: &str, text2: &str) -> HashSet { - let a: HashSet = text1.chars().collect(); - let b: HashSet = text2.chars().collect(); - a.intersection(&b).copied().collect() +fn celkovy_plat_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap { + let mut mapa: HashMap = HashMap::new(); + for z in zamestnanci { + *mapa.entry(z.oddelenie.clone()).or_insert(0) += z.plat; + } + mapa } ``` -## HS-3 +## 10c ```rust -fn ma_duplikaty(cisla: &[i32]) -> bool { - let mut videne = HashSet::new(); - for c in cisla { - if !videne.insert(c) { - return true; - } +fn vypis_statistiky(zamestnanci: &[Zamestnanec]) { + let pocty = pocet_na_oddeleni(zamestnanci); + let platy = celkovy_plat_na_oddeleni(zamestnanci); + for (oddelenie, pocet) in &pocty { + let plat = platy.get(oddelenie).unwrap_or(&0); + println!("{}: {} ľudí, celkový plat: {}", oddelenie, pocet, plat); } - false -} - -// Alebo kratšie (ale menej efektívne — prejde celý vektor): -fn ma_duplikaty(cisla: &[i32]) -> bool { - let mnozina: HashSet<&i32> = cisla.iter().collect(); - mnozina.len() != cisla.len() } ``` -## HS-4 +## 10d ```rust -fn unikatne_slova(text: &str) -> usize { - let mnozina: HashSet = text.split_whitespace() - .map(|s| s.to_lowercase()) - .collect(); - mnozina.len() -} -``` - -## HS-5 - -```rust -// a) -fn spolocni(a: &[String], b: &[String]) -> Vec { - let set_a: HashSet<&String> = a.iter().collect(); - let set_b: HashSet<&String> = b.iter().collect(); - set_a.intersection(&set_b).map(|s| (*s).clone()).collect() -} - -// b) -fn len_v_prvom(a: &[String], b: &[String]) -> Vec { - let set_a: HashSet<&String> = a.iter().collect(); - let set_b: HashSet<&String> = b.iter().collect(); - set_a.difference(&set_b).map(|s| (*s).clone()).collect() -} -``` - -## HS-6 - -```rust -use rand::seq::SliceRandom; - -struct Slovnik { - slova: HashMap>, -} - -impl Slovnik { - // a) - fn new() -> Slovnik { - Slovnik { slova: HashMap::new() } - } - - // b) - fn pridaj_kategoriu(&mut self, kategoria: &str) { - self.slova.entry(kategoria.to_string()).or_default(); - } - - // c) - fn pridaj_slovo(&mut self, kategoria: &str, slovo: &str) -> Result<(), ()> { - let kat = self.slova.get_mut(kategoria).ok_or(())?; - kat.push(slovo.to_string()); - Ok(()) - } - - // d) - fn nahodne_slovo(&self, kategoria: &str) -> Option<&String> { - let kat = self.slova.get(kategoria)?; - let mut rng = rand::thread_rng(); - kat.choose(&mut rng) - } - - // e) - fn vsetky_kategorie(&self) -> Vec<&String> { - self.slova.keys().collect() - } - - // f) - fn pocet_slov_v_kategorii(&self, kategoria: &str) -> Option { - self.slova.get(kategoria).map(|v| v.len()) - } -} -``` - -## K-1 - -```rust -struct Student { - meno: String, - predmety: HashSet, - znamky: HashMap, -} - -impl Student { - // a) - fn pridaj_predmet(&mut self, predmet: &str) { - self.predmety.insert(predmet.to_string()); - } - - // b) - fn zadaj_znamku(&mut self, predmet: &str, znamka: u8) -> Result<(), ()> { - if !self.predmety.contains(predmet) { - return Err(()); - } - self.znamky.insert(predmet.to_string(), znamka); - Ok(()) - } - - // c) - fn priemer(&self) -> Option { - if self.znamky.is_empty() { - return None; - } - let sucet: u32 = self.znamky.values().map(|z| *z as u32).sum(); - Some(sucet as f64 / self.znamky.len() as f64) - } - - // d) - fn spolocne_predmety(s1: &Student, s2: &Student) -> HashSet { - s1.predmety.intersection(&s2.predmety).cloned().collect() - } - - // e) - fn ma_vsetky_znamky(&self) -> bool { - self.predmety.iter().all(|p| self.znamky.contains_key(p)) - } -} -``` - -## K-2 - -```rust -struct Skola { - studenti: Vec, -} - -impl Skola { - // a) - fn vsetky_predmety(&self) -> HashSet { - let mut vsetky = HashSet::new(); - for student in &self.studenti { - for predmet in &student.predmety { - vsetky.insert(predmet.clone()); - } - } - vsetky - } - - // Alternatíva s iterátormi: - // fn vsetky_predmety(&self) -> HashSet { - // self.studenti.iter() - // .flat_map(|s| s.predmety.iter().cloned()) - // .collect() - // } - - // b) - fn studenti_s_predmetom(&self, predmet: &str) -> Vec<&Student> { - self.studenti.iter() - .filter(|s| s.predmety.contains(predmet)) - .collect() - } - - // c) - fn priemer_za_predmet(&self, predmet: &str) -> Option { - let znamky: Vec = self.studenti.iter() - .filter_map(|s| s.znamky.get(predmet).copied()) - .collect(); - if znamky.is_empty() { - return None; - } - let sucet: u32 = znamky.iter().map(|z| *z as u32).sum(); - Some(sucet as f64 / znamky.len() as f64) - } - - // d) - fn najlepsi_student(&self) -> Option<&Student> { - self.studenti.iter() - .filter(|s| !s.znamky.is_empty()) - .min_by(|a, b| { - let priemer_a = a.priemer().unwrap(); - let priemer_b = b.priemer().unwrap(); - priemer_a.partial_cmp(&priemer_b).unwrap() - }) - } +fn oddelenie_s_najvyssim_platom(zamestnanci: &[Zamestnanec]) -> Option { + let platy = celkovy_plat_na_oddeleni(zamestnanci); + platy.into_iter() + .max_by_key(|(_, plat)| *plat) + .map(|(oddelenie, _)| oddelenie) } ```