From fac12bc6651f7193f3e577626bd15eba09dcdb51 Mon Sep 17 00:00:00 2001 From: Priec Date: Thu, 26 Feb 2026 18:59:33 +0100 Subject: [PATCH] btreemap and hashset --- priprava/rust_priprava5.md | 276 +++++++++++++++++++++ priprava/rust_priprava6.md | 474 +++++++++++++++++++++++++++++++++++++ 2 files changed, 750 insertions(+) create mode 100644 priprava/rust_priprava5.md create mode 100644 priprava/rust_priprava6.md diff --git a/priprava/rust_priprava5.md b/priprava/rust_priprava5.md new file mode 100644 index 0000000..a959530 --- /dev/null +++ b/priprava/rust_priprava5.md @@ -0,0 +1,276 @@ +# BTreeMap — krok za krokom + +Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej. + +```rust +use std::collections::BTreeMap; // toto treba vždy +``` + +--- + +## Kapitola 1: Čo to je a rozdiel oproti HashMap + +BTreeMap je to isté ako HashMap — kľúč → hodnota — ale s jedným veľkým rozdielom: **kľúče sú vždy zoradené**. + +| | HashMap | BTreeMap | +|-|---------|----------| +| Poradie kľúčov | náhodné | zoradené (od najmenšieho) | +| Rýchlosť | O(1) | O(log n) | +| Kedy použiť | väčšinou | keď potrebuješ zoradené kľúče | +| Import | `use std::collections::HashMap` | `use std::collections::BTreeMap` | + +```rust +use std::collections::BTreeMap; + +let mut mapa = BTreeMap::new(); +mapa.insert("Cyril".to_string(), 22); +mapa.insert("Anna".to_string(), 25); +mapa.insert("Boris".to_string(), 30); + +// Iterácia — kľúče SÚ zoradené abecedne! +for (meno, vek) in &mapa { + println!("{}: {}", meno, vek); +} +// Anna: 25 +// Boris: 30 +// Cyril: 22 +``` + +S HashMap by poradie bolo náhodné. S BTreeMap je vždy zoradené. + +Pre čísla zoradí od najmenšieho: +```rust +let mut mapa = BTreeMap::new(); +mapa.insert(3, "tri"); +mapa.insert(1, "jedna"); +mapa.insert(2, "dva"); + +for (k, v) in &mapa { + println!("{}: {}", k, v); +} +// 1: jedna +// 2: dva +// 3: tri +``` + +### Úlohy 1 + +**1a.** Vytvor BTreeMap s 5 menami (String) a vekmi (u32). Vypíš ich. Over, že sú zoradené abecedne. + +**1b.** Vytvor BTreeMap s číslami ako kľúčmi (i32 → String). Vlož ich v náhodnom poradí. Vypíš a over, že sú zoradené. + +**1c.** Vytvor rovnakú mapu raz ako HashMap, raz ako BTreeMap. Vypíš obe. Vidíš rozdiel v poradí? + +--- + +## Kapitola 2: Všetko čo vieš z HashMap funguje rovnako + +BTreeMap má **rovnaké API** ako HashMap. Všetko čo si sa naučil, funguje: + +```rust +let mut mapa = BTreeMap::new(); + +// insert — rovnaké +mapa.insert("Anna".to_string(), 25); +let stara = mapa.insert("Anna".to_string(), 26); // Some(25) + +// get — rovnaké +let vek = mapa.get("Anna"); // Some(&26) + +// contains_key — rovnaké +let je_tam = mapa.contains_key("Anna"); // true + +// remove — rovnaké +let odstraneny = mapa.remove("Anna"); // Some(26) + +// len, is_empty — rovnaké +let pocet = mapa.len(); +let prazdna = mapa.is_empty(); + +// entry API — rovnaké! +*mapa.entry("Boris".to_string()).or_insert(0) += 1; +mapa.entry("Cyril".to_string()).or_default(); +mapa.entry("Dana".to_string()) + .and_modify(|v| *v += 1) + .or_insert(1); + +// get_mut — rovnaké +if let Some(vek) = mapa.get_mut("Boris") { + *vek += 10; +} + +// iterácia — rovnaká syntax, ale ZORADENÉ +for (k, v) in &mapa { /* zoradené podľa kľúča */ } +for k in mapa.keys() { /* zoradené */ } +for v in mapa.values() { /* v poradí podľa zoradených kľúčov */ } +for v in mapa.values_mut() { *v += 1; } +``` + +Jediný rozdiel je, že výstup je vždy zoradený. + +### Úlohy 2 + +**2a.** Spočítaj výskyt každého znaku v `"abrakadabra"` do BTreeMap. Vypíš. V akom poradí sú znaky? + +**2b.** Máš vektor slov. Zoskup ich podľa prvého písmena do `BTreeMap>`. Over, že písmená sú zoradené. + +**2c.** Napíš funkciu: +```rust +fn pocitaj_slova(text: &str) -> BTreeMap +``` +Počet výskytov každého slova, zoradené abecedne. + +--- + +## Kapitola 3: Range queries — to čo HashMap nevie + +Najväčšia výhoda BTreeMap: vieš sa pýtať na **rozsahy** kľúčov. + +### range — podmnožina podľa rozsahu kľúčov + +```rust +let mut mapa = BTreeMap::new(); +mapa.insert(1, "jedna"); +mapa.insert(2, "dva"); +mapa.insert(3, "tri"); +mapa.insert(4, "štyri"); +mapa.insert(5, "päť"); +mapa.insert(6, "šesť"); +mapa.insert(7, "sedem"); + +// Kľúče od 3 do 5 (vrátane oboch) +for (k, v) in mapa.range(3..=5) { + println!("{}: {}", k, v); +} +// 3: tri +// 4: štyri +// 5: päť + +// Kľúče od 3 (bez 6) +for (k, v) in mapa.range(3..6) { + println!("{}: {}", k, v); +} +// 3: tri +// 4: štyri +// 5: päť + +// Kľúče od začiatku po 3 (vrátane) +for (k, v) in mapa.range(..=3) { + println!("{}: {}", k, v); +} +// 1: jedna +// 2: dva +// 3: tri + +// Kľúče od 5 do konca +for (k, v) in mapa.range(5..) { + println!("{}: {}", k, v); +} +// 5: päť +// 6: šesť +// 7: sedem +``` + +S Stringami to funguje abecedne: +```rust +let mut mapa = BTreeMap::new(); +mapa.insert("Anna".to_string(), 25); +mapa.insert("Boris".to_string(), 30); +mapa.insert("Cyril".to_string(), 22); +mapa.insert("Dana".to_string(), 28); + +// Mená od "B" po "D" (nezahrnie "D" lebo ..) +for (meno, vek) in mapa.range("B".to_string().."D".to_string()) { + println!("{}: {}", meno, vek); +} +// Boris: 30 +// Cyril: 22 +``` + +### Úlohy 3 + +**3a.** Vytvor BTreeMap s kľúčmi 1 až 10 (i32 → String s názvom čísla). Vypíš len čísla 4 až 7. + +**3b.** Máš BTreeMap študentov (meno → priemer). Vypíš len študentov, ktorých meno začína na písmená M až Z. Použi `.range()`. + +**3c.** Máš BTreeMap teplôt za dni v mesiaci (u32 → f64, deň → teplota). Napíš funkciu: +```rust +fn teploty_v_tyzdni(teploty: &BTreeMap, od: u32, do_: u32) -> Vec +``` +Vráti vektor teplôt pre dané dni. + +--- + +## Kapitola 4: first/last — prvý a posledný kľúč + +BTreeMap vie efektívne nájsť najmenší a najväčší kľúč: + +```rust +let mut mapa = BTreeMap::new(); +mapa.insert(5, "päť"); +mapa.insert(1, "jedna"); +mapa.insert(9, "deväť"); +mapa.insert(3, "tri"); + +// Prvý (najmenší) pár +let prvy = mapa.first_key_value(); +// Some((&1, &"jedna")) + +// Posledný (najväčší) pár +let posledny = mapa.last_key_value(); +// Some((&9, &"deväť")) + +// Len kľúče +let prvy_kluc = mapa.keys().next(); // Some(&1) +let posledny_kluc = mapa.keys().last(); // Some(&9) +``` + +Tieto operácie sú O(log n) — veľmi rýchle. HashMap toto nevie (musel by prejsť celú mapu). + +### Úlohy 4 + +**4a.** Máš BTreeMap študentov (meno → priemer). Nájdi študenta s menom prvým v abecede a posledným v abecede. + +**4b.** Máš BTreeMap (rok: u32 → udalosť: String). Nájdi najstaršiu a najnovšiu udalosť. + +--- + +## Kapitola 5: Kedy HashMap, kedy BTreeMap + +| Situácia | Použi | +|----------|-------| +| Nepotrebuješ poradie | HashMap (rýchlejší) | +| Chceš zoradený výpis | BTreeMap | +| Potrebuješ range queries | BTreeMap | +| Potrebuješ prvý/posledný | BTreeMap | +| Chceš maximálny výkon | HashMap | +| Na skúške: `vypis_statistiky` zoradene | BTreeMap | + +**Tip na skúšku:** Ak zadanie hovorí "vypíš v abecednom poradí" alebo "zoradene", použi BTreeMap. Inak HashMap stačí. + +Konverzia medzi nimi je jednoduchá: +```rust +use std::collections::{HashMap, BTreeMap}; + +// HashMap → BTreeMap +let hash: HashMap = /* ... */; +let btree: BTreeMap = hash.into_iter().collect(); + +// BTreeMap → HashMap +let btree: BTreeMap = /* ... */; +let hash: HashMap = btree.into_iter().collect(); +``` + +### Úlohy 5 + +**5a.** Máš: +```rust +struct Zamestnanec { meno: String, oddelenie: String, plat: u32 } +``` +Napíš funkciu `pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> BTreeMap` — počet ľudí na oddelení, výstup zoradený podľa názvu oddelenia. + +**5b.** Máš vektor slov. Spočítaj výskyt každého slova a výstup zoradeného (BTreeMap). Potom vypíš len slová, ktoré sa vyskytli viac ako 2x. + +**5c.** Máš BTreeMap známok študenta (predmet → známka). Napíš funkcie: +- `najlepsia_znamka(znamky: &BTreeMap) -> Option<(&String, &u8)>` — predmet s najlepšou (najnižšou) známkou +- `predmety_v_rozsahu(znamky: &BTreeMap, od: &str, do_: &str) -> Vec<(&String, &u8)>` — predmety s názvom v danom abecednom rozsahu diff --git a/priprava/rust_priprava6.md b/priprava/rust_priprava6.md new file mode 100644 index 0000000..e363af1 --- /dev/null +++ b/priprava/rust_priprava6.md @@ -0,0 +1,474 @@ +# HashSet — krok za krokom + +Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej. + +```rust +use std::collections::HashSet; // toto treba vždy +``` + +--- + +## Kapitola 1: Čo to je a vytváranie + +HashSet je kolekcia **unikátnych hodnôt**. Žiadna hodnota sa neopakuje. Negarantuje poradie. + +Rozdiel oproti Vec: Vec môže mať duplikáty a pamätá poradie. +Rozdiel oproti HashMap: HashMap má kľúč → hodnota. HashSet má len hodnotu (žiadny pár). + +```rust +// Prázdny set +let mut mnozina: HashSet = HashSet::new(); + +// Alebo nechaj Rust odvodiť: +let mut mnozina = HashSet::new(); +mnozina.insert(1); // teraz Rust vie: HashSet + +// Z vektora — duplikáty zmiznú! +let cisla = vec![1, 2, 3, 2, 1, 4, 3, 5]; +let unikatne: HashSet = cisla.into_iter().collect(); +// {1, 2, 3, 4, 5} — len 5 prvkov, nie 8 + +// Z reťazca — množina znakov +let znaky: HashSet = "abrakadabra".chars().collect(); +// {'a', 'b', 'r', 'k', 'd'} — len 5 unikátnych +``` + +### Úlohy 1 + +**1a.** Vytvor HashSet čísel z vektora `[5, 3, 5, 1, 3, 2, 1, 4]`. Vypíš koľko prvkov má. Vypíš prvky. + +**1b.** Vytvor HashSet znakov z reťazca `"hello world"`. Koľko unikátnych znakov to má? (vrátane medzery) + +**1c.** Čo vypíše? Tipni, potom over: +```rust +let v = vec![10, 20, 10, 30, 20, 10]; +let s: HashSet = v.into_iter().collect(); +println!("{}", s.len()); +``` + +--- + +## Kapitola 2: insert — vráti bool! + +Toto je kľúčový rozdiel oproti HashMap. `insert` vráti `bool`: +- `true` → prvok bol **nový**, vložil sa +- `false` → prvok už **existoval**, nič sa nezmenilo + +```rust +let mut mnozina = HashSet::new(); + +let novy = mnozina.insert("Anna".to_string()); +// novy = true — Anna bola pridaná + +let novy = mnozina.insert("Anna".to_string()); +// novy = false — Anna už existuje, nič sa nezmenilo +``` + +**Praktické — detekcia duplikátov:** +```rust +let mut videne = HashSet::new(); +let slova = vec!["ahoj", "svet", "ahoj", "rust"]; + +for slovo in &slova { + if !videne.insert(*slovo) { + println!("Duplikát: {}", slovo); + } +} +// Vypíše: Duplikát: ahoj +``` + +Logika: `insert` vráti `false` → prvok tam už bol → je to duplikát. + +### Úlohy 2 + +**2a.** Napíš funkciu `ma_duplikaty(cisla: &[i32]) -> bool`. Použi HashSet a insert. Vráť true hneď ako nájdeš prvý duplikát. + +**2b.** Napíš funkciu `najdi_duplikaty(cisla: &[i32]) -> Vec` — vráti vektor všetkých duplikovaných hodnôt (každý duplikát len raz). Hint: použi dva HashSety — `videne` a `duplikaty`. + +**2c.** Čo vypíše? Tipni: +```rust +let mut s = HashSet::new(); +println!("{}", s.insert(1)); +println!("{}", s.insert(2)); +println!("{}", s.insert(1)); +println!("{}", s.insert(3)); +println!("{}", s.insert(2)); +``` + +--- + +## Kapitola 3: contains, remove, len + +```rust +let mut mnozina = HashSet::new(); +mnozina.insert("Anna".to_string()); +mnozina.insert("Boris".to_string()); + +// contains — je tam? +mnozina.contains("Anna"); // true +mnozina.contains("Cyril"); // false + +// len — počet prvkov +mnozina.len(); // 2 + +// is_empty +mnozina.is_empty(); // false + +// remove — vráti bool (true ak existoval a bol odstránený) +mnozina.remove("Anna"); // true — Anna odstránená +mnozina.remove("Cyril"); // false — Cyril tam ani nebol + +// clear — vymaž všetko +mnozina.clear(); +``` + +**Dôležité:** `contains` na HashSet je O(1) — veľmi rýchle. Na Vec je O(n) — pomalé. Ak často kontroluješ existenciu, použi HashSet. + +```rust +// POMALÉ — Vec.contains prechádza celý vektor +let povolene = vec!["admin", "editor", "viewer"]; +povolene.contains(&"admin"); // O(n) + +// RÝCHLE — HashSet.contains +let povolene: HashSet<&str> = vec!["admin", "editor", "viewer"].into_iter().collect(); +povolene.contains("admin"); // O(1) +``` + +### Úlohy 3 + +**3a.** Vytvor HashSet povolených farieb: "červená", "modrá", "zelená". Napíš funkciu: +```rust +fn je_povolena(povolene: &HashSet, farba: &str) -> bool +``` + +**3b.** Napíš funkciu `pocet_unikatnych(cisla: &[i32]) -> usize` — koľko rôznych hodnôt je vo vektore. + +**3c.** Máš HashSet mien. Odstráň všetky mená kratšie ako 4 znaky. Použi `.retain()`: +```rust +// retain nechá len prvky, kde closure vráti true +mnozina.retain(|meno| meno.len() >= 4); +``` + +--- + +## Kapitola 4: Iterácia + +```rust +let mnozina: HashSet = vec![3, 1, 4, 1, 5].into_iter().collect(); + +// Základná iterácia — poradie NIE JE garantované! +for prvok in &mnozina { + println!("{}", prvok); +} + +// filter + collect — vyfiltruj do nového HashSetu +let parne: HashSet<&i32> = mnozina.iter().filter(|c| *c % 2 == 0).collect(); + +// Do Vec +let vektor: Vec<&i32> = mnozina.iter().collect(); + +// any — existuje prvok splňajúci podmienku? +let ma_velke: bool = mnozina.iter().any(|c| *c > 3); + +// count s filtrom +let pocet_parnych: usize = mnozina.iter().filter(|c| *c % 2 == 0).count(); + +// sum +let sucet: i32 = mnozina.iter().sum(); +``` + +### Úlohy 4 + +**4a.** Máš HashSet mien (String). Vypíš len mená začínajúce na 'A'. + +**4b.** Napíš funkciu `sucet(mnozina: &HashSet) -> i32` — súčet všetkých prvkov. + +**4c.** Napíš funkciu `najdlhsi(mnozina: &HashSet) -> Option<&String>` — najdlhší reťazec. Použi `.max_by_key()`. + +**4d.** Máš HashSet čísel. Koľko z nich je deliteľných 3? Napíš to jedným výrazom. + +--- + +## Kapitola 5: Prienik (intersection) + +Prienik = prvky, ktoré sú v **oboch** množinách. + +```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 cez &i32 +let prienik: HashSet<&i32> = a.intersection(&b).collect(); +// {&3, &4} + +// Ak chceš vlastné hodnoty (nie referencie), použi .copied() +let prienik: HashSet = a.intersection(&b).copied().collect(); +// {3, 4} + +// Alebo do Vec +let prienik: Vec<&i32> = a.intersection(&b).collect(); +// [&3, &4] +``` + +**Skratka operátorom:** +```rust +let prienik: HashSet = &a & &b; +// {3, 4} — rovnaký výsledok, kratší zápis +``` + +### Úlohy 5 + +**5a.** Máš dva zoznamy mien (Vec). Preveď ich na HashSety a nájdi spoločné mená. +```rust +let trieda_a = vec!["Anna", "Boris", "Cyril", "Dana"]; +let trieda_b = vec!["Boris", "Dana", "Emil", "Fero"]; +// Spoločné: Boris, Dana +``` + +**5b.** Napíš funkciu: +```rust +fn spolocne_pismena(slovo1: &str, slovo2: &str) -> HashSet +``` +Vráti písmená, ktoré sú v oboch slovách. + +**5c.** Máš 3 HashSety. Nájdi prvky, ktoré sú vo všetkých troch. Hint: najprv prienik A∩B, potom výsledok ∩ C. + +--- + +## Kapitola 6: Zjednotenie (union) + +Zjednotenie = prvky, ktoré sú v **aspoň jednej** z množín. Duplikáty sa nezopakujú. + +```rust +let a: HashSet = vec![1, 2, 3].into_iter().collect(); +let b: HashSet = vec![3, 4, 5].into_iter().collect(); + +let zjednotenie: HashSet<&i32> = a.union(&b).collect(); +// {&1, &2, &3, &4, &5} + +let zjednotenie: HashSet = a.union(&b).copied().collect(); +// {1, 2, 3, 4, 5} +``` + +**Skratka:** +```rust +let zjednotenie: HashSet = &a | &b; +``` + +### Úlohy 6 + +**6a.** Máš záujmy dvoch ľudí ako HashSety. Nájdi všetky záujmy dokopy (bez duplikátov). + +**6b.** Napíš funkciu: +```rust +fn vsetky_unikatne_znaky(texty: &[String]) -> HashSet +``` +Vráti množinu všetkých znakov zo všetkých textov. Hint: iteruj cez texty a postupne rob union, alebo jednoducho insertuj do jedného HashSetu. + +--- + +## Kapitola 7: Rozdiel (difference) + +Rozdiel = prvky v **prvej**, ktoré nie sú v **druhej**. + +```rust +let a: HashSet = vec![1, 2, 3, 4].into_iter().collect(); +let b: HashSet = vec![3, 4, 5, 6].into_iter().collect(); + +// Prvky v A, ktoré NIE SÚ v B +let rozdiel: HashSet = a.difference(&b).copied().collect(); +// {1, 2} + +// Opačný smer — prvky v B, ktoré NIE SÚ v A +let rozdiel_opacny: HashSet = b.difference(&a).copied().collect(); +// {5, 6} +``` + +**Skratka:** +```rust +let rozdiel: HashSet = &a - &b; // {1, 2} +``` + +**Symetrický rozdiel** = prvky v jednej ALEBO druhej, ale nie v oboch: +```rust +let sym: HashSet = a.symmetric_difference(&b).copied().collect(); +// {1, 2, 5, 6} + +// Skratka: +let sym: HashSet = &a ^ &b; +``` + +### Úlohy 7 + +**7a.** Máš zoznam všetkých študentov a zoznam prítomných. Nájdi kto chýba: +```rust +let vsetci: HashSet = /* Anna, Boris, Cyril, Dana, Emil */; +let pritomni: HashSet = /* Anna, Cyril, Emil */; +// Chýba: Boris, Dana +``` + +**7b.** Napíš funkciu: +```rust +fn chybajuce_pismena(slovo: &str) -> HashSet +``` +Vráti písmená abecedy (a-z), ktoré sa v slove nenachádzajú. Hint: `('a'..='z').collect()` ti dá HashSet celej abecedy. + +**7c.** Máš dva Vec. Nájdi čísla, ktoré sú len v jednom z nich (nie v oboch). Použi symetrický rozdiel. + +--- + +## Kapitola 8: Podmnožina, nadmnožina, disjunkcia + +```rust +let mala: HashSet = vec![1, 2].into_iter().collect(); +let velka: HashSet = vec![1, 2, 3, 4].into_iter().collect(); +let ina: HashSet = vec![5, 6].into_iter().collect(); + +// is_subset — je mala podmnožinou velka? +mala.is_subset(&velka); // true — všetky prvky mala sú vo velka + +// is_superset — je velka nadmnožinou mala? +velka.is_superset(&mala); // true — velka obsahuje všetko z mala + +// is_disjoint — nemajú nič spoločné? +mala.is_disjoint(&ina); // true — žiadny spoločný prvok +mala.is_disjoint(&velka); // false — majú spoločné 1 a 2 +``` + +### Úlohy 8 + +**8a.** Máš povinné predmety a predmety, ktoré študent absolvoval. Napíš funkciu: +```rust +fn splnil_vsetky(povinne: &HashSet, absolvovane: &HashSet) -> bool +``` +Vráti true ak absolvoval všetky povinné. Jeden riadok. + +**8b.** Máš dve skupiny ľudí. Napíš funkciu, ktorá zistí, či sa skupiny vôbec neprekrývajú: +```rust +fn su_nezavisle(a: &HashSet, b: &HashSet) -> bool +``` + +**8c.** Študent má predmety. Máš set povinných, set voliteľných. Napíš: +- `splnil_povinne(studentove: &HashSet, povinne: &HashSet) -> bool` +- `ktore_povinne_chybaju(studentove: &HashSet, povinne: &HashSet) -> HashSet` — ktoré povinné mu ešte chýbajú + +--- + +## Kapitola 9: Prehľad operátorov + +Všetky množinové operácie majú aj skrátený zápis: + +```rust +let a: HashSet = vec![1, 2, 3].into_iter().collect(); +let b: HashSet = vec![2, 3, 4].into_iter().collect(); + +let prienik = &a & &b; // {2, 3} +let zjednotenie = &a | &b; // {1, 2, 3, 4} +let rozdiel = &a - &b; // {1} +let sym_rozdiel = &a ^ &b; // {1, 4} +``` + +Všetky vracajú nový `HashSet` (nie referencie). Pozor na `&a` — treba referencie. + +### Úlohy 9 + +**9a.** Máš tri sety A, B, C. Napíš jedným výrazom s operátormi: +- prvky, ktoré sú vo všetkých troch +- prvky, ktoré sú v aspoň jednom +- prvky, ktoré sú v A ale nie v B ani v C + +--- + +## Kapitola 10: Praktické vzory zo skúšky + +### Vzor 1: Obesenec — sledovanie uhádnutých písmen + +```rust +struct Obesenec { + slovo: String, + uhadnute: HashSet, + skusane: HashSet, + zivoty: u8, +} + +impl Obesenec { + fn new(slovo: &str) -> Obesenec { + Obesenec { + slovo: slovo.to_lowercase(), + uhadnute: HashSet::new(), + skusane: HashSet::new(), + zivoty: 6, + } + } + + fn tipni(&mut self, pismeno: char) -> &str { + let p = pismeno.to_lowercase().next().unwrap(); + + // insert vráti false ak písmeno už bolo skúšané + if !self.skusane.insert(p) { + return "Už si skúšal"; + } + + if self.slovo.contains(p) { + self.uhadnute.insert(p); + "Správne" + } else { + self.zivoty -= 1; + "Zle" + } + } + + // Zobraz slovo: uhádnuté písmená, neuhádnuté ako '_' + fn zobraz(&self) -> String { + self.slovo.chars().map(|c| { + if self.uhadnute.contains(&c) { c } else { '_' } + }).collect() + } + + // Vyhral ak všetky písmená slova sú v uhadnute + fn vyhral(&self) -> bool { + self.slovo.chars().all(|c| self.uhadnute.contains(&c)) + } +} +``` + +Kľúčové veci: +- `skusane.insert(p)` vráti `false` → písmeno už bolo → preskočíme +- `uhadnute.contains(&c)` → rýchla kontrola pre každý znak slova +- `slovo.chars().all(|c| uhadnute.contains(&c))` → vyhral ak uhádol všetky + +### Vzor 2: Unikátne hodnoty z kolekcie štruktúr + +```rust +struct Kniha { nazov: String, zaner: String } + +fn unikatne_zanre(knihy: &[Kniha]) -> HashSet { + knihy.iter().map(|k| k.zaner.clone()).collect() +} +``` + +### Vzor 3: Rýchle vyhľadávanie v cykle + +```rust +// Ak kontroluješ contains opakovane, preveď Vec na HashSet +fn najdi_spolocne(kniznica: &[Kniha], pozicane_nazvy: &[String]) -> Vec<&Kniha> { + let nazvy_set: HashSet<&String> = pozicane_nazvy.iter().collect(); + kniznica.iter() + .filter(|k| nazvy_set.contains(&k.nazov)) + .collect() +} +``` + +### Úlohy 10 + +**10a.** Implementuj Obesenca sám od nuly. Musíš mať: +- `new(slovo: &str) -> Obesenec` +- `tipni(&mut self, pismeno: char) -> bool` — true ak správne +- `zobraz(&self) -> String` — slovo s '_' za neuhádnuté +- `je_koniec(&self) -> bool` — true ak vyhral alebo zivoty == 0 + +**10b.** Máš vektor študentov s `predmety: Vec`. Napíš: +- `vsetky_predmety(studenti: &[Student]) -> HashSet` +- `studenti_s_predmetom(studenti: &[Student], predmet: &str) -> Vec<&Student>` + +**10c.** Máš `povinne_predmety: HashSet` a `absolvovane: HashSet`. Vypíš: koľko povinných splnil, koľko mu chýba, ktoré mu chýbajú.