summaryrefslogtreecommitdiff
path: root/rustlings
diff options
context:
space:
mode:
authorHunter Kvalevog <hunter@kvog.sh>2026-09-27 11:08:08 -0500
committerHunter Kvalevog <hunter@kvog.sh>2026-09-27 11:08:08 -0500
commit0fcfd332dd5057a590371c28ed3e6b267f788b76 (patch)
treee7fbb66a21de3e7613d81eb8a592d2709afec81b /rustlings
parent4abf853ebed9608583a39b13ab3cd3f14ecd1f4b (diff)
rustlings: complete 11
Diffstat (limited to 'rustlings')
-rw-r--r--rustlings/.rustlings-state.txt8
-rw-r--r--rustlings/exercises/11_hashmaps/hashmaps1.rs5
-rw-r--r--rustlings/exercises/11_hashmaps/hashmaps2.rs8
-rw-r--r--rustlings/exercises/11_hashmaps/hashmaps3.rs7
-rw-r--r--rustlings/exercises/quizzes/quiz2.rs18
-rw-r--r--rustlings/solutions/11_hashmaps/hashmaps1.rs42
-rw-r--r--rustlings/solutions/11_hashmaps/hashmaps2.rs96
-rw-r--r--rustlings/solutions/11_hashmaps/hashmaps3.rs85
-rw-r--r--rustlings/solutions/quizzes/quiz2.rs90
9 files changed, 345 insertions, 14 deletions
diff --git a/rustlings/.rustlings-state.txt b/rustlings/.rustlings-state.txt
index e195870..8b4959e 100644
--- a/rustlings/.rustlings-state.txt
+++ b/rustlings/.rustlings-state.txt
@@ -1,6 +1,6 @@
DON'T EDIT THIS FILE!
-hashmaps1
+options1
intro1
intro2
@@ -44,4 +44,8 @@ strings3
strings4
modules1
modules2
-modules3 \ No newline at end of file
+modules3
+hashmaps1
+hashmaps2
+hashmaps3
+quiz2 \ No newline at end of file
diff --git a/rustlings/exercises/11_hashmaps/hashmaps1.rs b/rustlings/exercises/11_hashmaps/hashmaps1.rs
index 74001d0..a746b32 100644
--- a/rustlings/exercises/11_hashmaps/hashmaps1.rs
+++ b/rustlings/exercises/11_hashmaps/hashmaps1.rs
@@ -8,12 +8,15 @@ use std::collections::HashMap;
fn fruit_basket() -> HashMap<String, u32> {
// TODO: Declare the hash map.
- // let mut basket =
+ let mut basket = HashMap::new();
// Two bananas are already given for you :)
basket.insert(String::from("banana"), 2);
// TODO: Put more fruits in your basket.
+ basket.insert(String::from("banana"), 1);
+ basket.insert(String::from("orange"), 140000);
+ basket.insert(String::from("strawberry"), 5);
basket
}
diff --git a/rustlings/exercises/11_hashmaps/hashmaps2.rs b/rustlings/exercises/11_hashmaps/hashmaps2.rs
index e9f53fe..482db7c 100644
--- a/rustlings/exercises/11_hashmaps/hashmaps2.rs
+++ b/rustlings/exercises/11_hashmaps/hashmaps2.rs
@@ -29,9 +29,11 @@ fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
];
for fruit in fruit_kinds {
- // TODO: Insert new fruits if they are not already present in the
- // basket. Note that you are not allowed to put any type of fruit that's
- // already present!
+ // This works just fine, but clippy doesn't like how readable and obvious the code is
+ // if !basket.contains_key(&fruit) {
+ // basket.insert(fruit, 10);
+ // }
+ basket.entry(fruit).or_insert(10);
}
}
diff --git a/rustlings/exercises/11_hashmaps/hashmaps3.rs b/rustlings/exercises/11_hashmaps/hashmaps3.rs
index 5b390ab..0fa4a6b 100644
--- a/rustlings/exercises/11_hashmaps/hashmaps3.rs
+++ b/rustlings/exercises/11_hashmaps/hashmaps3.rs
@@ -31,6 +31,13 @@ fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
// Keep in mind that goals scored by team 1 will be the number of goals
// conceded by team 2. Similarly, goals scored by team 2 will be the
// number of goals conceded by team 1.
+ let team_1 = scores.entry(team_1_name).or_default();
+ team_1.goals_scored += team_1_score;
+ team_1.goals_conceded += team_2_score;
+ let team_2 = scores.entry(team_2_name).or_default();
+ team_2.goals_scored += team_2_score;
+ team_2.goals_conceded += team_1_score;
+
}
scores
diff --git a/rustlings/exercises/quizzes/quiz2.rs b/rustlings/exercises/quizzes/quiz2.rs
index 2cddba9..fd32810 100644
--- a/rustlings/exercises/quizzes/quiz2.rs
+++ b/rustlings/exercises/quizzes/quiz2.rs
@@ -28,6 +28,23 @@ mod my_module {
// TODO: Complete the function as described above.
// pub fn transformer(input: ???) -> ??? { ??? }
+ pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
+ let mut out = Vec::new();
+ for inp in input {
+ out.push(match inp.1 {
+ Command::Uppercase => inp.0.to_uppercase(),
+ Command::Trim => String::from(inp.0.trim()),
+ Command::Append(n) => {
+ let mut r = inp.0;
+ for _ in 0..n {
+ r += "bar";
+ }
+ r
+ }
+ });
+ }
+ out
+ }
}
fn main() {
@@ -39,6 +56,7 @@ mod tests {
// TODO: What do we need to import to have `transformer` in scope?
// use ???;
use super::Command;
+ use super::my_module::transformer;
#[test]
fn it_works() {
diff --git a/rustlings/solutions/11_hashmaps/hashmaps1.rs b/rustlings/solutions/11_hashmaps/hashmaps1.rs
index dcf2377..3a787c4 100644
--- a/rustlings/solutions/11_hashmaps/hashmaps1.rs
+++ b/rustlings/solutions/11_hashmaps/hashmaps1.rs
@@ -1,4 +1,42 @@
+// A basket of fruits in the form of a hash map needs to be defined. The key
+// represents the name of the fruit and the value represents how many of that
+// particular fruit is in the basket. You have to put at least 3 different
+// types of fruits (e.g apple, banana, mango) in the basket and the total count
+// of all the fruits should be at least 5.
+
+use std::collections::HashMap;
+
+fn fruit_basket() -> HashMap<String, u32> {
+ // Declare the hash map.
+ let mut basket = HashMap::new();
+
+ // Two bananas are already given for you :)
+ basket.insert(String::from("banana"), 2);
+
+ // Put more fruits in your basket.
+ basket.insert(String::from("apple"), 3);
+ basket.insert(String::from("mango"), 1);
+
+ basket
+}
+
fn main() {
- // DON'T EDIT THIS SOLUTION FILE!
- // It will be automatically filled after you finish the exercise.
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn at_least_three_types_of_fruits() {
+ let basket = fruit_basket();
+ assert!(basket.len() >= 3);
+ }
+
+ #[test]
+ fn at_least_five_fruits() {
+ let basket = fruit_basket();
+ assert!(basket.values().sum::<u32>() >= 5);
+ }
}
diff --git a/rustlings/solutions/11_hashmaps/hashmaps2.rs b/rustlings/solutions/11_hashmaps/hashmaps2.rs
index dcf2377..75e6ec2 100644
--- a/rustlings/solutions/11_hashmaps/hashmaps2.rs
+++ b/rustlings/solutions/11_hashmaps/hashmaps2.rs
@@ -1,4 +1,96 @@
+// We're collecting different fruits to bake a delicious fruit cake. For this,
+// we have a basket, which we'll represent in the form of a hash map. The key
+// represents the name of each fruit we collect and the value represents how
+// many of that particular fruit we have collected. Three types of fruits -
+// Apple (4), Mango (2) and Lychee (5) are already in the basket hash map. You
+// must add fruit to the basket so that there is at least one of each kind and
+// more than 11 in total - we have a lot of mouths to feed. You are not allowed
+// to insert any more of the fruits that are already in the basket (Apple,
+// Mango, and Lychee).
+
+use std::collections::HashMap;
+
+#[derive(Hash, PartialEq, Eq, Debug)]
+enum Fruit {
+ Apple,
+ Banana,
+ Mango,
+ Lychee,
+ Pineapple,
+}
+
+fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
+ let fruit_kinds = [
+ Fruit::Apple,
+ Fruit::Banana,
+ Fruit::Mango,
+ Fruit::Lychee,
+ Fruit::Pineapple,
+ ];
+
+ for fruit in fruit_kinds {
+ // If fruit doesn't exist, insert it with some value.
+ basket.entry(fruit).or_insert(5);
+ }
+}
+
fn main() {
- // DON'T EDIT THIS SOLUTION FILE!
- // It will be automatically filled after you finish the exercise.
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // Don't modify this function!
+ fn get_fruit_basket() -> HashMap<Fruit, u32> {
+ let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
+ HashMap::from_iter(content)
+ }
+
+ #[test]
+ fn test_given_fruits_are_not_modified() {
+ let mut basket = get_fruit_basket();
+ fruit_basket(&mut basket);
+ assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
+ assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
+ assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
+ }
+
+ #[test]
+ fn at_least_five_types_of_fruits() {
+ let mut basket = get_fruit_basket();
+ fruit_basket(&mut basket);
+ let count_fruit_kinds = basket.len();
+ assert!(count_fruit_kinds >= 5);
+ }
+
+ #[test]
+ fn greater_than_eleven_fruits() {
+ let mut basket = get_fruit_basket();
+ fruit_basket(&mut basket);
+ let count = basket.values().sum::<u32>();
+ assert!(count > 11);
+ }
+
+ #[test]
+ fn all_fruit_types_in_basket() {
+ let fruit_kinds = [
+ Fruit::Apple,
+ Fruit::Banana,
+ Fruit::Mango,
+ Fruit::Lychee,
+ Fruit::Pineapple,
+ ];
+
+ let mut basket = get_fruit_basket();
+ fruit_basket(&mut basket);
+
+ for fruit_kind in fruit_kinds {
+ let Some(amount) = basket.get(&fruit_kind) else {
+ panic!("Fruit kind {fruit_kind:?} was not found in basket");
+ };
+ assert!(*amount > 0);
+ }
+ }
}
diff --git a/rustlings/solutions/11_hashmaps/hashmaps3.rs b/rustlings/solutions/11_hashmaps/hashmaps3.rs
index dcf2377..485bf83 100644
--- a/rustlings/solutions/11_hashmaps/hashmaps3.rs
+++ b/rustlings/solutions/11_hashmaps/hashmaps3.rs
@@ -1,4 +1,85 @@
+// A list of scores (one per line) of a soccer match is given. Each line is of
+// the form "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>"
+// Example: "England,France,4,2" (England scored 4 goals, France 2).
+//
+// You have to build a scores table containing the name of the team, the total
+// number of goals the team scored, and the total number of goals the team
+// conceded.
+
+use std::collections::HashMap;
+
+// A structure to store the goal details of a team.
+#[derive(Default)]
+struct TeamScores {
+ goals_scored: u8,
+ goals_conceded: u8,
+}
+
+fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
+ // The name of the team is the key and its associated struct is the value.
+ let mut scores = HashMap::<&str, TeamScores>::new();
+
+ for line in results.lines() {
+ let mut split_iterator = line.split(',');
+ // NOTE: We use `unwrap` because we didn't deal with error handling yet.
+ let team_1_name = split_iterator.next().unwrap();
+ let team_2_name = split_iterator.next().unwrap();
+ let team_1_score: u8 = split_iterator.next().unwrap().parse().unwrap();
+ let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
+
+ // Insert the default with zeros if a team doesn't exist yet.
+ let team_1 = scores.entry(team_1_name).or_default();
+ // Update the values.
+ team_1.goals_scored += team_1_score;
+ team_1.goals_conceded += team_2_score;
+
+ // Similarly for the second team.
+ let team_2 = scores.entry(team_2_name).or_default();
+ team_2.goals_scored += team_2_score;
+ team_2.goals_conceded += team_1_score;
+ }
+
+ scores
+}
+
fn main() {
- // DON'T EDIT THIS SOLUTION FILE!
- // It will be automatically filled after you finish the exercise.
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ const RESULTS: &str = "England,France,4,2
+France,Italy,3,1
+Poland,Spain,2,0
+Germany,England,2,1
+England,Spain,1,0";
+
+ #[test]
+ fn build_scores() {
+ let scores = build_scores_table(RESULTS);
+
+ assert!(
+ ["England", "France", "Germany", "Italy", "Poland", "Spain"]
+ .into_iter()
+ .all(|team_name| scores.contains_key(team_name))
+ );
+ }
+
+ #[test]
+ fn validate_team_score_1() {
+ let scores = build_scores_table(RESULTS);
+ let team = scores.get("England").unwrap();
+ assert_eq!(team.goals_scored, 6);
+ assert_eq!(team.goals_conceded, 4);
+ }
+
+ #[test]
+ fn validate_team_score_2() {
+ let scores = build_scores_table(RESULTS);
+ let team = scores.get("Spain").unwrap();
+ assert_eq!(team.goals_scored, 0);
+ assert_eq!(team.goals_conceded, 3);
+ }
}
diff --git a/rustlings/solutions/quizzes/quiz2.rs b/rustlings/solutions/quizzes/quiz2.rs
index dcf2377..8b073b1 100644
--- a/rustlings/solutions/quizzes/quiz2.rs
+++ b/rustlings/solutions/quizzes/quiz2.rs
@@ -1,4 +1,90 @@
+// Let's build a little machine in the form of a function. As input, we're going
+// to give a list of strings and commands. These commands determine what action
+// is going to be applied to the string. It can either be:
+// - Uppercase the string
+// - Trim the string
+// - Append "bar" to the string a specified amount of times
+//
+// The exact form of this will be:
+// - The input is going to be a vector of 2-length tuples,
+// the first element is the string, the second one is the command.
+// - The output element is going to be a vector of strings.
+
+enum Command {
+ Uppercase,
+ Trim,
+ Append(usize),
+}
+
+mod my_module {
+ use super::Command;
+
+ // The solution with a loop. Check out `transformer_iter` for a version
+ // with iterators.
+ pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
+ let mut output = Vec::new();
+
+ for (string, command) in input {
+ // Create the new string.
+ let new_string = match command {
+ Command::Uppercase => string.to_uppercase(),
+ Command::Trim => string.trim().to_string(),
+ Command::Append(n) => string + &"bar".repeat(n),
+ };
+
+ // Push the new string to the output vector.
+ output.push(new_string);
+ }
+
+ output
+ }
+
+ // Equivalent to `transform` but uses an iterator instead of a loop for
+ // comparison. Don't worry, we will practice iterators later ;)
+ pub fn transformer_iter(input: Vec<(String, Command)>) -> Vec<String> {
+ input
+ .into_iter()
+ .map(|(string, command)| match command {
+ Command::Uppercase => string.to_uppercase(),
+ Command::Trim => string.trim().to_string(),
+ Command::Append(n) => string + &"bar".repeat(n),
+ })
+ .collect()
+ }
+}
+
fn main() {
- // DON'T EDIT THIS SOLUTION FILE!
- // It will be automatically filled after you finish the exercise.
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ // Import `transformer`.
+ use super::my_module::transformer;
+
+ use super::Command;
+ use super::my_module::transformer_iter;
+
+ #[test]
+ fn it_works() {
+ for transformer in [transformer, transformer_iter] {
+ let input = vec![
+ ("hello".to_string(), Command::Uppercase),
+ (" all roads lead to rome! ".to_string(), Command::Trim),
+ ("foo".to_string(), Command::Append(1)),
+ ("bar".to_string(), Command::Append(5)),
+ ];
+ let output = transformer(input);
+
+ assert_eq!(
+ output,
+ [
+ "HELLO",
+ "all roads lead to rome!",
+ "foobar",
+ "barbarbarbarbarbar",
+ ]
+ );
+ }
+ }
}