btreemap and hashset
This commit is contained in:
276
priprava/rust_priprava5.md
Normal file
276
priprava/rust_priprava5.md
Normal file
@@ -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<char, Vec<String>>`. Over, že písmená sú zoradené.
|
||||
|
||||
**2c.** Napíš funkciu:
|
||||
```rust
|
||||
fn pocitaj_slova(text: &str) -> BTreeMap<String, usize>
|
||||
```
|
||||
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<u32, f64>, od: u32, do_: u32) -> Vec<f64>
|
||||
```
|
||||
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<String, i32> = /* ... */;
|
||||
let btree: BTreeMap<String, i32> = hash.into_iter().collect();
|
||||
|
||||
// BTreeMap → HashMap
|
||||
let btree: BTreeMap<String, i32> = /* ... */;
|
||||
let hash: HashMap<String, i32> = 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<String, usize>` — 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<String, u8>) -> Option<(&String, &u8)>` — predmet s najlepšou (najnižšou) známkou
|
||||
- `predmety_v_rozsahu(znamky: &BTreeMap<String, u8>, od: &str, do_: &str) -> Vec<(&String, &u8)>` — predmety s názvom v danom abecednom rozsahu
|
||||
474
priprava/rust_priprava6.md
Normal file
474
priprava/rust_priprava6.md
Normal file
@@ -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<i32> = HashSet::new();
|
||||
|
||||
// Alebo nechaj Rust odvodiť:
|
||||
let mut mnozina = HashSet::new();
|
||||
mnozina.insert(1); // teraz Rust vie: HashSet<i32>
|
||||
|
||||
// Z vektora — duplikáty zmiznú!
|
||||
let cisla = vec![1, 2, 3, 2, 1, 4, 3, 5];
|
||||
let unikatne: HashSet<i32> = cisla.into_iter().collect();
|
||||
// {1, 2, 3, 4, 5} — len 5 prvkov, nie 8
|
||||
|
||||
// Z reťazca — množina znakov
|
||||
let znaky: HashSet<char> = "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<i32> = 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<i32>` — 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<String>, 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<i32> = 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>) -> i32` — súčet všetkých prvkov.
|
||||
|
||||
**4c.** Napíš funkciu `najdlhsi(mnozina: &HashSet<String>) -> 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<i32> = vec![1, 2, 3, 4].into_iter().collect();
|
||||
let b: HashSet<i32> = 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<i32> = 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<i32> = &a & &b;
|
||||
// {3, 4} — rovnaký výsledok, kratší zápis
|
||||
```
|
||||
|
||||
### Úlohy 5
|
||||
|
||||
**5a.** Máš dva zoznamy mien (Vec<String>). 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<char>
|
||||
```
|
||||
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<i32> = vec![1, 2, 3].into_iter().collect();
|
||||
let b: HashSet<i32> = vec![3, 4, 5].into_iter().collect();
|
||||
|
||||
let zjednotenie: HashSet<&i32> = a.union(&b).collect();
|
||||
// {&1, &2, &3, &4, &5}
|
||||
|
||||
let zjednotenie: HashSet<i32> = a.union(&b).copied().collect();
|
||||
// {1, 2, 3, 4, 5}
|
||||
```
|
||||
|
||||
**Skratka:**
|
||||
```rust
|
||||
let zjednotenie: HashSet<i32> = &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<char>
|
||||
```
|
||||
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<i32> = vec![1, 2, 3, 4].into_iter().collect();
|
||||
let b: HashSet<i32> = vec![3, 4, 5, 6].into_iter().collect();
|
||||
|
||||
// Prvky v A, ktoré NIE SÚ v B
|
||||
let rozdiel: HashSet<i32> = a.difference(&b).copied().collect();
|
||||
// {1, 2}
|
||||
|
||||
// Opačný smer — prvky v B, ktoré NIE SÚ v A
|
||||
let rozdiel_opacny: HashSet<i32> = b.difference(&a).copied().collect();
|
||||
// {5, 6}
|
||||
```
|
||||
|
||||
**Skratka:**
|
||||
```rust
|
||||
let rozdiel: HashSet<i32> = &a - &b; // {1, 2}
|
||||
```
|
||||
|
||||
**Symetrický rozdiel** = prvky v jednej ALEBO druhej, ale nie v oboch:
|
||||
```rust
|
||||
let sym: HashSet<i32> = a.symmetric_difference(&b).copied().collect();
|
||||
// {1, 2, 5, 6}
|
||||
|
||||
// Skratka:
|
||||
let sym: HashSet<i32> = &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<String> = /* Anna, Boris, Cyril, Dana, Emil */;
|
||||
let pritomni: HashSet<String> = /* Anna, Cyril, Emil */;
|
||||
// Chýba: Boris, Dana
|
||||
```
|
||||
|
||||
**7b.** Napíš funkciu:
|
||||
```rust
|
||||
fn chybajuce_pismena(slovo: &str) -> HashSet<char>
|
||||
```
|
||||
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<i32>. 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<i32> = vec![1, 2].into_iter().collect();
|
||||
let velka: HashSet<i32> = vec![1, 2, 3, 4].into_iter().collect();
|
||||
let ina: HashSet<i32> = 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<String>, absolvovane: &HashSet<String>) -> 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<String>, b: &HashSet<String>) -> bool
|
||||
```
|
||||
|
||||
**8c.** Študent má predmety. Máš set povinných, set voliteľných. Napíš:
|
||||
- `splnil_povinne(studentove: &HashSet<String>, povinne: &HashSet<String>) -> bool`
|
||||
- `ktore_povinne_chybaju(studentove: &HashSet<String>, povinne: &HashSet<String>) -> HashSet<String>` — 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<i32> = vec![1, 2, 3].into_iter().collect();
|
||||
let b: HashSet<i32> = 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<i32>` (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<char>,
|
||||
skusane: HashSet<char>,
|
||||
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<String> {
|
||||
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<String>`. Napíš:
|
||||
- `vsetky_predmety(studenti: &[Student]) -> HashSet<String>`
|
||||
- `studenti_s_predmetom(studenti: &[Student], predmet: &str) -> Vec<&Student>`
|
||||
|
||||
**10c.** Máš `povinne_predmety: HashSet<String>` a `absolvovane: HashSet<String>`. Vypíš: koľko povinných splnil, koľko mu chýba, ktoré mu chýbajú.
|
||||
Reference in New Issue
Block a user