Skip to content

Commit 01785a9

Browse files
committed
day2 rework (revert iterators & macros chapters; shorten exercises)
1 parent 358d6af commit 01785a9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+5266
-1676
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,9 @@ target
2020
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
2121
#.idea/
2222

23+
# Course participant solutions
24+
solutions/*/
25+
!solutions/.gitkeep
26+
2327
# Claude Code assistant file
2428
CLAUDE.md

mdbook/book/day1/01_setup.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,22 @@ <h2 id="key-takeaways"><a class="header" href="#key-takeaways">Key Takeaways</a>
340340

341341
</div>
342342

343+
<!-- Livereload script (if served using the cli tool) -->
344+
<script>
345+
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
346+
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
347+
const socket = new WebSocket(wsAddress);
348+
socket.onmessage = function (event) {
349+
if (event.data === "reload") {
350+
socket.close();
351+
location.reload();
352+
}
353+
};
354+
355+
window.onbeforeunload = function() {
356+
socket.close();
357+
}
358+
</script>
343359

344360

345361

mdbook/book/day1/02_fundamentals.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,22 @@ <h2 id="additional-resources"><a class="header" href="#additional-resources">Add
934934

935935
</div>
936936

937+
<!-- Livereload script (if served using the cli tool) -->
938+
<script>
939+
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
940+
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
941+
const socket = new WebSocket(wsAddress);
942+
socket.onmessage = function (event) {
943+
if (event.data === "reload") {
944+
socket.close();
945+
location.reload();
946+
}
947+
};
948+
949+
window.onbeforeunload = function() {
950+
socket.close();
951+
}
952+
</script>
937953

938954

939955

mdbook/book/day1/03_structs_enums.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,22 @@ <h3 id="exercise-3-state-machine-for-a-traffic-light"><a class="header" href="#e
834834

835835
</div>
836836

837+
<!-- Livereload script (if served using the cli tool) -->
838+
<script>
839+
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
840+
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
841+
const socket = new WebSocket(wsAddress);
842+
socket.onmessage = function (event) {
843+
if (event.data === "reload") {
844+
socket.close();
845+
location.reload();
846+
}
847+
};
848+
849+
window.onbeforeunload = function() {
850+
socket.close();
851+
}
852+
</script>
837853

838854

839855

mdbook/book/day1/04_ownership.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,22 @@ <h3 id="exercise-3-lifetime-annotations"><a class="header" href="#exercise-3-lif
854854

855855
</div>
856856

857+
<!-- Livereload script (if served using the cli tool) -->
858+
<script>
859+
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
860+
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
861+
const socket = new WebSocket(wsAddress);
862+
socket.onmessage = function (event) {
863+
if (event.data === "reload") {
864+
socket.close();
865+
location.reload();
866+
}
867+
};
868+
869+
window.onbeforeunload = function() {
870+
socket.close();
871+
}
872+
</script>
857873

858874

859875

mdbook/book/day1/05_smart_pointers.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,22 @@ <h2 id="additional-resources"><a class="header" href="#additional-resources">Add
10061006

10071007
</div>
10081008

1009+
<!-- Livereload script (if served using the cli tool) -->
1010+
<script>
1011+
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
1012+
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
1013+
const socket = new WebSocket(wsAddress);
1014+
socket.onmessage = function (event) {
1015+
if (event.data === "reload") {
1016+
socket.close();
1017+
location.reload();
1018+
}
1019+
};
1020+
1021+
window.onbeforeunload = function() {
1022+
socket.close();
1023+
}
1024+
</script>
10091025

10101026

10111027

mdbook/book/day2/06_collections.html

Lines changed: 143 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -388,90 +388,151 @@ <h3 id="borrowing-during-iteration"><a class="header" href="#borrowing-during-it
388388
}
389389
<span class="boring">}</span></code></pre></pre>
390390
<hr />
391-
<h2 id="exercise-build-a-cache-system"><a class="header" href="#exercise-build-a-cache-system">Exercise: Build a Cache System</a></h2>
392-
<p>Create an LRU (Least Recently Used) cache with expiration:</p>
393-
<pre><pre class="playground"><code class="language-rust">use std::collections::{HashMap, VecDeque};
394-
use std::time::{Duration, Instant};
395-
396-
struct CacheEntry&lt;V&gt; {
397-
value: V,
398-
last_accessed: Instant,
399-
expires_at: Option&lt;Instant&gt;,
391+
<h2 id="exercise-student-grade-management-system"><a class="header" href="#exercise-student-grade-management-system">Exercise: Student Grade Management System</a></h2>
392+
<p>Create a system that manages student grades using HashMap and HashSet to practice collections operations and the Entry API:</p>
393+
<pre><pre class="playground"><code class="language-rust">use std::collections::{HashMap, HashSet};
394+
395+
#[derive(Debug)]
396+
struct GradeBook {
397+
// Student name -&gt; HashMap of (subject -&gt; grade)
398+
grades: HashMap&lt;String, HashMap&lt;String, f64&gt;&gt;,
399+
// Set of all subjects offered
400+
subjects: HashSet&lt;String&gt;,
400401
}
401402

402-
struct LRUCache&lt;K: Clone + Eq + std::hash::Hash, V&gt; {
403-
capacity: usize,
404-
cache: HashMap&lt;K, CacheEntry&lt;V&gt;&gt;,
405-
access_order: VecDeque&lt;K&gt;,
406-
}
407-
408-
impl&lt;K: Clone + Eq + std::hash::Hash, V: Clone&gt; LRUCache&lt;K, V&gt; {
409-
fn new(capacity: usize) -&gt; Self {
410-
LRUCache {
411-
capacity,
412-
cache: HashMap::new(),
413-
access_order: VecDeque::new(),
403+
impl GradeBook {
404+
fn new() -&gt; Self {
405+
GradeBook {
406+
grades: HashMap::new(),
407+
subjects: HashSet::new(),
414408
}
415409
}
416-
417-
fn get(&amp;mut self, key: &amp;K) -&gt; Option&lt;&amp;V&gt; {
418-
// TODO: Check if key exists
419-
// TODO: Check if entry is expired (remove if expired)
420-
// TODO: Update last_accessed time
421-
// TODO: Move key to end of access_order (most recently used)
422-
// TODO: Return the value
410+
411+
fn add_subject(&amp;mut self, subject: String) {
412+
// TODO: Add subject to the subjects set
423413
todo!()
424414
}
425-
426-
fn insert(&amp;mut self, key: K, value: V, ttl: Option&lt;Duration&gt;) {
427-
// TODO: If at capacity, remove least recently used item
428-
// TODO: Create cache entry with expiration if ttl provided
429-
// TODO: Add to cache and access_order
415+
416+
fn add_grade(&amp;mut self, student: String, subject: String, grade: f64) {
417+
// TODO: Add a grade for a student in a subject
418+
// Hints:
419+
// 1. Add subject to subjects set
420+
// 2. Use entry() API to get or create the student's grade map
421+
// 3. Insert the grade for the subject
430422
todo!()
431423
}
432-
433-
fn remove(&amp;mut self, key: &amp;K) -&gt; Option&lt;V&gt; {
434-
// TODO: Remove from cache and access_order
435-
// TODO: Return the value if it existed
424+
425+
fn get_student_average(&amp;self, student: &amp;str) -&gt; Option&lt;f64&gt; {
426+
// TODO: Calculate average grade for a student across all their subjects
427+
// Return None if student doesn't exist
428+
// Hint: Use .values() and iterator methods
436429
todo!()
437430
}
438-
439-
fn clear_expired(&amp;mut self) {
440-
// TODO: Remove all expired entries
431+
432+
fn get_subject_average(&amp;self, subject: &amp;str) -&gt; Option&lt;f64&gt; {
433+
// TODO: Calculate average grade for a subject across all students
434+
// Return None if no students have grades in this subject
441435
todo!()
442436
}
443-
444-
fn stats(&amp;self) -&gt; (usize, usize) {
445-
// Return (current_size, capacity)
446-
(self.cache.len(), self.capacity)
437+
438+
fn get_students_in_subject(&amp;self, subject: &amp;str) -&gt; Vec&lt;&amp;String&gt; {
439+
// TODO: Return list of students who have a grade in the given subject
440+
// Hint: Filter students who have this subject in their grade map
441+
todo!()
442+
}
443+
444+
fn get_top_students(&amp;self, n: usize) -&gt; Vec&lt;(String, f64)&gt; {
445+
// TODO: Return top N students by average grade
446+
// Format: Vec&lt;(student_name, average_grade)&gt;
447+
// Hint: Calculate averages, collect into Vec, sort, and take top N
448+
todo!()
449+
}
450+
451+
fn remove_student(&amp;mut self, student: &amp;str) -&gt; bool {
452+
// TODO: Remove a student and all their grades
453+
// Return true if student existed, false otherwise
454+
todo!()
455+
}
456+
457+
fn list_subjects(&amp;self) -&gt; Vec&lt;&amp;String&gt; {
458+
// TODO: Return all subjects as a sorted vector
459+
todo!()
447460
}
448461
}
449462

450463
fn main() {
451-
let mut cache = LRUCache::new(3);
452-
453-
// Test basic operations
454-
cache.insert("user:1", "Alice", Some(Duration::from_secs(60)));
455-
cache.insert("user:2", "Bob", None); // No expiration
456-
cache.insert("user:3", "Charlie", Some(Duration::from_secs(5)));
457-
458-
// Access user:1 to make it most recently used
459-
println!("Got: {:?}", cache.get(&amp;"user:1"));
460-
461-
// Add one more - should evict user:2 (least recently used)
462-
cache.insert("user:4", "David", None);
463-
464-
// Try to get user:2 - should be None (evicted)
465-
println!("User 2 (should be evicted): {:?}", cache.get(&amp;"user:2"));
466-
467-
let (size, capacity) = cache.stats();
468-
println!("Cache stats - Size: {}/{}", size, capacity);
464+
let mut gradebook = GradeBook::new();
465+
466+
// Add subjects
467+
gradebook.add_subject("Math".to_string());
468+
gradebook.add_subject("English".to_string());
469+
gradebook.add_subject("Science".to_string());
470+
471+
// Add grades for students
472+
gradebook.add_grade("Alice".to_string(), "Math".to_string(), 95.0);
473+
gradebook.add_grade("Alice".to_string(), "English".to_string(), 87.0);
474+
gradebook.add_grade("Bob".to_string(), "Math".to_string(), 82.0);
475+
gradebook.add_grade("Bob".to_string(), "Science".to_string(), 91.0);
476+
gradebook.add_grade("Charlie".to_string(), "English".to_string(), 78.0);
477+
gradebook.add_grade("Charlie".to_string(), "Science".to_string(), 85.0);
478+
479+
// Test the methods
480+
if let Some(avg) = gradebook.get_student_average("Alice") {
481+
println!("Alice's average: {:.2}", avg);
482+
}
483+
484+
if let Some(avg) = gradebook.get_subject_average("Math") {
485+
println!("Math class average: {:.2}", avg);
486+
}
487+
488+
let math_students = gradebook.get_students_in_subject("Math");
489+
println!("Students in Math: {:?}", math_students);
490+
491+
let top_students = gradebook.get_top_students(2);
492+
println!("Top 2 students: {:?}", top_students);
493+
494+
println!("All subjects: {:?}", gradebook.list_subjects());
469495
}</code></pre></pre>
470-
<p><strong>Hints:</strong></p>
496+
<p><strong>Implementation Hints:</strong></p>
497+
<ol>
498+
<li>
499+
<p><strong>add_grade() method:</strong></p>
500+
<ul>
501+
<li>Use <code>self.grades.entry(student).or_insert_with(HashMap::new)</code></li>
502+
<li>Then insert the grade: <code>.insert(subject, grade)</code></li>
503+
</ul>
504+
</li>
505+
<li>
506+
<p><strong>get_student_average():</strong></p>
471507
<ul>
472-
<li>Use <code>VecDeque::retain()</code> to keep only non-expired keys</li>
473-
<li>HashMap’s <code>entry()</code> API is useful for get-or-insert patterns</li>
474-
<li>Remember to update both the HashMap and VecDeque when modifying</li>
508+
<li>Use <code>self.grades.get(student)?</code> to get the student’s grades</li>
509+
<li>Use <code>.values().sum::&lt;f64&gt;() / values.len() as f64</code></li>
510+
</ul>
511+
</li>
512+
<li>
513+
<p><strong>get_subject_average():</strong></p>
514+
<ul>
515+
<li>Iterate through all students: <code>self.grades.iter()</code></li>
516+
<li>Filter students who have this subject: <code>filter_map(|(_, grades)| grades.get(subject))</code></li>
517+
<li>Calculate average from the filtered grades</li>
518+
</ul>
519+
</li>
520+
<li>
521+
<p><strong>get_top_students():</strong></p>
522+
<ul>
523+
<li>Use <code>map()</code> to convert students to (name, average) pairs</li>
524+
<li>Use <code>collect::&lt;Vec&lt;_&gt;&gt;()</code> and <code>sort_by()</code> with float comparison</li>
525+
<li>Use <code>take(n)</code> to get top N</li>
526+
</ul>
527+
</li>
528+
</ol>
529+
<p><strong>What you’ll learn:</strong></p>
530+
<ul>
531+
<li>HashMap’s Entry API for efficient insertions</li>
532+
<li>HashSet for tracking unique values</li>
533+
<li>Nested HashMap structures</li>
534+
<li>Iterator methods for data processing</li>
535+
<li>Working with Option types from HashMap lookups</li>
475536
</ul>
476537
<hr />
477538
<h2 id="key-takeaways"><a class="header" href="#key-takeaways">Key Takeaways</a></h2>
@@ -514,6 +575,22 @@ <h2 id="key-takeaways"><a class="header" href="#key-takeaways">Key Takeaways</a>
514575

515576
</div>
516577

578+
<!-- Livereload script (if served using the cli tool) -->
579+
<script>
580+
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
581+
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
582+
const socket = new WebSocket(wsAddress);
583+
socket.onmessage = function (event) {
584+
if (event.data === "reload") {
585+
socket.close();
586+
location.reload();
587+
}
588+
};
589+
590+
window.onbeforeunload = function() {
591+
socket.close();
592+
}
593+
</script>
517594

518595

519596

0 commit comments

Comments
 (0)