# Rust — HashMap a HashSet kompletný sprievodca --- ## 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). ```rust use std::collections::HashMap; ``` Toto musíš importovať vždy. Nie je v prelude (na rozdiel od Vec alebo String). --- ## 2. HashMap — vytváranie ### Prázdna mapa ```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) let stara = mapa.insert("Anna".to_string(), 26); // stara = Some(25) (kľúč existoval, stará hodnota bola 25, teraz je 26) ``` **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). --- ## 4. HashMap — čítanie ### get — vráti Option<&V> ```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 ``` ### get s &String vs &str ```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 } ``` --- ## 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 ```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á let odstraneny: Option = mapa.remove("Cyril"); // None — Cyril neexistoval // Vymaž všetko mapa.clear(); ``` --- ## 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 ```rust let mut mapa = HashMap::new(); 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é! for (meno, vek) in &mapa { println!("{}: {}", meno, vek); } // Len kľúče for meno in mapa.keys() { println!("{}", meno); } // Len hodnoty for vek in mapa.values() { println!("{}", vek); } // Meniteľná iterácia cez hodnoty for vek in mapa.values_mut() { *vek += 1; // všetkým pridaj rok } // Iterátor + collect — napr. 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(); ``` **Dôležité:** HashMap negarantuje poradie! Ak chceš zoradené, musíš po iterácii triediť alebo použiť BTreeMap. --- ## 9. HashMap — praktické vzory zo skúšky ### Vzor 1: Počítanie podľa kategórie ```rust struct Kniha { nazov: String, zaner: String } fn pocty_zanrov(knihy: &[Kniha]) -> HashMap { let mut mapa = HashMap::new(); for kniha in knihy { *mapa.entry(kniha.zaner.clone()).or_insert(0) += 1; } mapa } ``` ### Vzor 2: Výpis štatistík ```rust fn vypis_vydavatelstva_a_pocet(knihy: &[Kniha]) { let pocty = pocty_zanrov(knihy); for (zaner, pocet) in &pocty { println!("{}: {}", zaner, pocet); } } ``` ### Vzor 3: Zoskupenie do vektorov ```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); pocty.into_iter() .max_by_key(|(_, pocet)| *pocet) .map(|(zaner, _)| zaner) } ``` --- ## 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áš: ```rust struct Objednavka { zakaznik: String, suma: f64, mesto: String } ``` 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 **Ú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é"]} ``` **Ú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. --- --- ## 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) --- --- --- # RIEŠENIA ## HM-1 ```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 } ``` ## HM-2 ```rust struct Objednavka { zakaznik: String, suma: f64, mesto: String } // 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; } 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; } 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); } 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) } // e) fn najlepsi_zakaznik(objednavky: &[Objednavka]) -> Option { let sumy = celkova_suma_podla_zakaznika(objednavky); sumy.into_iter() .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap()) .map(|(zakaznik, _)| zakaznik) } ``` ## HM-3 ```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 } ``` ## HM-4 ```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) } ``` ## HS-1 ```rust fn unikatne_znaky(text: &str) -> HashSet { text.chars().filter(|c| *c != ' ').collect() } ``` ## HS-2 ```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() } ``` ## HS-3 ```rust fn ma_duplikaty(cisla: &[i32]) -> bool { let mut videne = HashSet::new(); for c in cisla { if !videne.insert(c) { return true; } } 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 ```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() }) } } ```