Compare commits

..

No commits in common. "61c7eaed6251fb8a28b00ea97b22d1f1b778a72b" and "746cf6863dee8f676596b07e74bad1a19fa2579e" have entirely different histories.

14 changed files with 205 additions and 576 deletions

View file

@ -29,8 +29,8 @@ mod tests {
// TODO: This test should check if the rectangle has the size that we
// pass to its constructor.
let rect = Rectangle::new(10, 20);
assert_eq!(todo!(), 10); // Check width
assert_eq!(todo!(), 20); // Check height
assert_eq!(???, 10); // Check width
assert_eq!(???, 20); // Check height
}
// TODO: This test should check if the program panics when we try to create

View file

@ -1,6 +1,8 @@
// When performing operations on elements within a collection, iterators are
// essential. This module helps you get familiar with the structure of using an
// iterator and how to go through elements within an iterable collection.
//
// Make me compile by filling in the `???`s
fn main() {
// You can optionally experiment here.
@ -8,18 +10,19 @@ fn main() {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iterators() {
let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"];
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];
// TODO: Create an iterator over the array.
let mut fav_fruits_iterator = todo!();
let mut my_iterable_fav_fruits = ???; // TODO: Step 1
assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 4
}
}

View file

@ -1,28 +1,31 @@
// In this exercise, you'll learn some of the unique advantages that iterators
// can offer.
// can offer. Follow the steps to complete the exercise.
// TODO: Complete the `capitalize_first` function.
// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello"
fn capitalize_first(input: &str) -> String {
let mut chars = input.chars();
match chars.next() {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => todo!(),
Some(first) => ???,
}
}
// TODO: Apply the `capitalize_first` function to a slice of string slices.
// Step 2.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
// ???
vec![]
}
// TODO: Apply the `capitalize_first` function again to a slice of string
// slices. Return a single string.
// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
fn capitalize_words_string(words: &[&str]) -> String {
// ???
String::new()
}
fn main() {

View file

@ -1,26 +1,40 @@
// This is a bigger exercise than most of the others! You can do it! Here is
// your mission, should you choose to accept it:
// 1. Complete the divide function to get the first four tests to pass.
// 2. Get the remaining tests to pass by completing the result_with_list and
// list_of_results functions.
#[derive(Debug, PartialEq, Eq)]
enum DivisionError {
NotDivisible(NotDivisibleError),
DivideByZero,
NotDivisible,
}
// TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
#[derive(Debug, PartialEq, Eq)]
struct NotDivisibleError {
dividend: i32,
divisor: i32,
}
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
// Otherwise, return a suitable error.
fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
todo!();
}
// TODO: Add the correct return type and complete the function body.
// Desired output: `Ok([1, 11, 1426, 3])`
fn result_with_list() {
let numbers = [27, 297, 38502, 81];
// Complete the function and return a value of the correct type so the test
// passes.
// Desired output: Ok([1, 11, 1426, 3])
fn result_with_list() -> () {
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
}
// TODO: Add the correct return type and complete the function body.
// Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]`
fn list_of_results() {
let numbers = [27, 297, 38502, 81];
// Complete the function and return a value of the correct type so the test
// passes.
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
fn list_of_results() -> () {
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
}
@ -38,13 +52,19 @@ mod tests {
}
#[test]
fn test_divide_by_0() {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
fn test_not_divisible() {
assert_eq!(
divide(81, 6),
Err(DivisionError::NotDivisible(NotDivisibleError {
dividend: 81,
divisor: 6
}))
);
}
#[test]
fn test_not_divisible() {
assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));
fn test_divide_by_0() {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
}
#[test]
@ -54,11 +74,14 @@ mod tests {
#[test]
fn test_result_with_list() {
assert_eq!(result_with_list().unwarp(), [1, 11, 1426, 3]);
assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");
}
#[test]
fn test_list_of_results() {
assert_eq!(list_of_results(), [Ok(1), Ok(11), Ok(1426), Ok(3)]);
assert_eq!(
format!("{:?}", list_of_results()),
"[Ok(1), Ok(11), Ok(1426), Ok(3)]"
);
}
}

View file

@ -1,9 +1,9 @@
fn factorial(num: u8) -> u64 {
// TODO: Complete this function to return the factorial of `num`.
fn factorial(num: u64) -> u64 {
// Complete this function to return the factorial of num
// Do not use:
// - early returns (using the `return` keyword explicitly)
// Try not to use:
// - imperative style loops (for/while)
// - imperative style loops (for, while)
// - additional variables
// For an extra challenge, don't use:
// - recursion
@ -19,20 +19,20 @@ mod tests {
#[test]
fn factorial_of_0() {
assert_eq!(factorial(0), 1);
assert_eq!(1, factorial(0));
}
#[test]
fn factorial_of_1() {
assert_eq!(factorial(1), 1);
assert_eq!(1, factorial(1));
}
#[test]
fn factorial_of_2() {
assert_eq!(factorial(2), 2);
assert_eq!(2, factorial(2));
}
#[test]
fn factorial_of_4() {
assert_eq!(factorial(4), 24);
assert_eq!(24, factorial(4));
}
}

View file

@ -1,8 +1,10 @@
// Let's define a simple model to track Rustlings' exercise progress. Progress
// Let's define a simple model to track Rustlings exercise progress. Progress
// will be modelled using a hash map. The name of the exercise is the key and
// the progress is the value. Two counting functions were created to count the
// number of exercises with a given progress. Recreate this counting
// functionality using iterators. Try to not use imperative loops (for/while).
// functionality using iterators. Try not to use imperative loops (for, while).
// Only the two iterator methods (count_iterator and count_collection_iterator)
// need to be modified.
use std::collections::HashMap;
@ -16,25 +18,24 @@ enum Progress {
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
let mut count = 0;
for val in map.values() {
if *val == value {
if val == &value {
count += 1;
}
}
count
}
// TODO: Implement the functionality of `count_for` but with an iterator instead
// of a `for` loop.
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
// `map` is a hash map with `String` keys and `Progress` values.
// map = { "variables1": Complete, "from_str": None, … }
// map is a hashmap with String keys and Progress values.
// map = { "variables1": Complete, "from_str": None, ... }
todo!();
}
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
let mut count = 0;
for map in collection {
for val in map.values() {
if *val == value {
if val == &value {
count += 1;
}
}
@ -42,12 +43,11 @@ fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progres
count
}
// TODO: Implement the functionality of `count_collection_for` but with an
// iterator instead of a `for` loop.
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
// `collection` is a slice of hash maps.
// collection = [{ "variables1": Complete, "from_str": None, … },
// { "variables2": Complete, … }, … ]
// collection is a slice of hashmaps.
// collection = [{ "variables1": Complete, "from_str": None, ... },
// { "variables2": Complete, ... }, ... ]
todo!();
}
fn main() {
@ -58,6 +58,70 @@ fn main() {
mod tests {
use super::*;
#[test]
fn count_complete() {
let map = get_map();
assert_eq!(3, count_iterator(&map, Progress::Complete));
}
#[test]
fn count_some() {
let map = get_map();
assert_eq!(1, count_iterator(&map, Progress::Some));
}
#[test]
fn count_none() {
let map = get_map();
assert_eq!(2, count_iterator(&map, Progress::None));
}
#[test]
fn count_complete_equals_for() {
let map = get_map();
let progress_states = vec![Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_for(&map, progress_state),
count_iterator(&map, progress_state)
);
}
}
#[test]
fn count_collection_complete() {
let collection = get_vec_map();
assert_eq!(
6,
count_collection_iterator(&collection, Progress::Complete)
);
}
#[test]
fn count_collection_some() {
let collection = get_vec_map();
assert_eq!(1, count_collection_iterator(&collection, Progress::Some));
}
#[test]
fn count_collection_none() {
let collection = get_vec_map();
assert_eq!(4, count_collection_iterator(&collection, Progress::None));
}
#[test]
fn count_collection_equals_for() {
let progress_states = vec![Progress::Complete, Progress::Some, Progress::None];
let collection = get_vec_map();
for progress_state in progress_states {
assert_eq!(
count_collection_for(&collection, progress_state),
count_collection_iterator(&collection, progress_state)
);
}
}
fn get_map() -> HashMap<String, Progress> {
use Progress::*;
@ -86,68 +150,4 @@ mod tests {
vec![map, other]
}
#[test]
fn count_complete() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::Complete), 3);
}
#[test]
fn count_some() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::Some), 1);
}
#[test]
fn count_none() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::None), 2);
}
#[test]
fn count_complete_equals_for() {
let map = get_map();
let progress_states = [Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_for(&map, progress_state),
count_iterator(&map, progress_state),
);
}
}
#[test]
fn count_collection_complete() {
let collection = get_vec_map();
assert_eq!(
count_collection_iterator(&collection, Progress::Complete),
6,
);
}
#[test]
fn count_collection_some() {
let collection = get_vec_map();
assert_eq!(count_collection_iterator(&collection, Progress::Some), 1);
}
#[test]
fn count_collection_none() {
let collection = get_vec_map();
assert_eq!(count_collection_iterator(&collection, Progress::None), 4);
}
#[test]
fn count_collection_equals_for() {
let collection = get_vec_map();
let progress_states = [Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_collection_for(&collection, progress_state),
count_collection_iterator(&collection, progress_state),
);
}
}
}

View file

@ -4,43 +4,45 @@
// `Box` - a smart pointer used to store data on the heap, which also allows us
// to wrap a recursive type.
//
// The recursive type we're implementing in this exercise is the "cons list", a
// The recursive type we're implementing in this exercise is the `cons list` - a
// data structure frequently found in functional programming languages. Each
// item in a cons list contains two elements: The value of the current item and
// item in a cons list contains two elements: the value of the current item and
// the next item. The last item is a value called `Nil`.
//
// Step 1: use a `Box` in the enum definition to make the code compile
// Step 2: create both empty and non-empty cons lists by replacing `todo!()`
//
// Note: the tests should not be changed
// TODO: Use a `Box` in the enum definition to make the code compile.
#[derive(PartialEq, Debug)]
enum List {
Cons(i32, List),
Nil,
}
// TODO: Create an empty cons list.
fn create_empty_list() -> List {
todo!()
}
// TODO: Create a non-empty cons list.
fn create_non_empty_list() -> List {
todo!()
}
fn main() {
println!("This is an empty cons list: {:?}", create_empty_list());
println!(
"This is a non-empty cons list: {:?}",
create_non_empty_list(),
create_non_empty_list()
);
}
fn create_empty_list() -> List {
todo!()
}
fn create_non_empty_list() -> List {
todo!()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_empty_list() {
assert_eq!(create_empty_list(), List::Nil);
assert_eq!(List::Nil, create_empty_list());
}
#[test]

View file

@ -886,15 +886,28 @@ https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html#checking-for-pa
name = "iterators1"
dir = "18_iterators"
hint = """
Step 1:
We need to apply something to the collection `my_fav_fruits` before we start to
go through it. What could that be? Take a look at the struct definition for a
vector for inspiration:
https://doc.rust-lang.org/std/vec/struct.Vec.html
Step 2 & step 3:
Very similar to the lines above and below. You've got this!
Step 4:
An iterator goes through all elements in a collection, but what if we've run
out of elements? What should we expect here? If you're stuck, take a look at
https://doc.rust-lang.org/std/iter/trait.Iterator.html"""
https://doc.rust-lang.org/std/iter/trait.Iterator.html for some ideas."""
[[exercises]]
name = "iterators2"
dir = "18_iterators"
hint = """
`capitalize_first`:
Step 1:
The variable `first` is a `char`. It needs to be capitalized and added to the
remaining characters in `c` in order to return the correct `String`.
@ -905,15 +918,12 @@ The remaining characters in `c` can be viewed as a string slice using the
The documentation for `char` contains many useful methods.
https://doc.rust-lang.org/std/primitive.char.html
Use `char::to_uppercase`. It returns an iterator that can be converted to a
`String`.
`capitalize_words_vector`:
Step 2:
Create an iterator from the slice. Transform the iterated values by applying
the `capitalize_first` function. Remember to `collect` the iterator.
`capitalize_words_string`:
Step 3:
This is surprisingly similar to the previous solution. `collect` is very
powerful and very general. Rust just needs to know the desired type."""
@ -922,8 +932,8 @@ powerful and very general. Rust just needs to know the desired type."""
name = "iterators3"
dir = "18_iterators"
hint = """
The `divide` function needs to return the correct error when the divisor is 0 or
when even division is not possible.
The `divide` function needs to return the correct error when even division is
not possible.
The `division_results` variable needs to be collected into a collection type.
@ -934,7 +944,7 @@ The `list_of_results` function needs to return a vector of results.
See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for
how the `FromIterator` trait is used in `collect()`. This trait is REALLY
powerful! It can make the solution to this exercise much easier."""
powerful! It can make the solution to this exercise infinitely easier."""
[[exercises]]
name = "iterators4"
@ -942,10 +952,10 @@ dir = "18_iterators"
hint = """
In an imperative language, you might write a `for` loop that updates a mutable
variable. Or, you might write code utilizing recursion and a match clause. In
Rust, you can take another functional approach, computing the factorial
Rust you can take another functional approach, computing the factorial
elegantly with ranges and iterators.
Check out the `fold` and `rfold` methods!"""
Hint 2: Check out the `fold` and `rfold` methods!"""
[[exercises]]
name = "iterators5"
@ -969,16 +979,21 @@ a different method that could make your code more compact than using `fold`."""
name = "box1"
dir = "19_smart_pointers"
hint = """
The compiler's message should help: Since we cannot store the value of the
Step 1:
The compiler's message should help: since we cannot store the value of the
actual type when working with recursive types, we need to store a reference
(pointer) to its value.
We should, therefore, place our `List` inside a `Box`. More details in The Book:
https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes
We should, therefore, place our `List` inside a `Box`. More details in the book
here: https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes
Creating an empty list should be fairly straightforward (Hint: Read the tests).
Step 2:
For a non-empty list, keep in mind that we want to use our `Cons` list builder.
Creating an empty list should be fairly straightforward (hint: peek at the
assertions).
For a non-empty list keep in mind that we want to use our `Cons` "list builder".
Although the current list is one of integers (`i32`), feel free to change the
definition and try other types!"""

View file

@ -1,26 +1 @@
// When performing operations on elements within a collection, iterators are
// essential. This module helps you get familiar with the structure of using an
// iterator and how to go through elements within an iterable collection.
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
#[test]
fn iterators() {
let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"];
// Create an iterator over the array.
let mut fav_fruits_iterator = my_fav_fruits.iter();
assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
assert_eq!(fav_fruits_iterator.next(), Some(&"custard apple"));
assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
assert_eq!(fav_fruits_iterator.next(), Some(&"peach"));
assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
assert_eq!(fav_fruits_iterator.next(), None);
// ^^^^ reached the end
}
}
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰

View file

@ -1,56 +1 @@
// In this exercise, you'll learn some of the unique advantages that iterators
// can offer.
// "hello" -> "Hello"
fn capitalize_first(input: &str) -> String {
let mut chars = input.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().to_string() + chars.as_str(),
}
}
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
words.iter().map(|word| capitalize_first(word)).collect()
}
// Apply the `capitalize_first` function again to a slice of string
// slices. Return a single string.
// ["hello", " ", "world"] -> "Hello World"
fn capitalize_words_string(words: &[&str]) -> String {
words.iter().map(|word| capitalize_first(word)).collect()
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_success() {
assert_eq!(capitalize_first("hello"), "Hello");
}
#[test]
fn test_empty() {
assert_eq!(capitalize_first(""), "");
}
#[test]
fn test_iterate_string_vec() {
let words = vec!["hello", "world"];
assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
}
#[test]
fn test_iterate_into_string() {
let words = vec!["hello", " ", "world"];
assert_eq!(capitalize_words_string(&words), "Hello World");
}
}
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰

View file

@ -1,73 +1 @@
#[derive(Debug, PartialEq, Eq)]
enum DivisionError {
DivideByZero,
NotDivisible,
}
fn divide(a: i64, b: i64) -> Result<i64, DivisionError> {
if b == 0 {
return Err(DivisionError::DivideByZero);
}
if a % b != 0 {
return Err(DivisionError::NotDivisible);
}
Ok(a / b)
}
fn result_with_list() -> Result<Vec<i64>, DivisionError> {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
let numbers = [27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
// Collects to the expected return type. Returns the first error in the
// division results (if one exists).
division_results.collect()
}
fn list_of_results() -> Vec<Result<i64, DivisionError>> {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
let numbers = [27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
// Collects to the expected return type.
division_results.collect()
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_success() {
assert_eq!(divide(81, 9), Ok(9));
}
#[test]
fn test_divide_by_0() {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
}
#[test]
fn test_not_divisible() {
assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));
}
#[test]
fn test_divide_0_by_something() {
assert_eq!(divide(0, 81), Ok(0));
}
#[test]
fn test_result_with_list() {
assert_eq!(result_with_list().unwrap(), [1, 11, 1426, 3]);
}
#[test]
fn test_list_of_results() {
assert_eq!(list_of_results(), [Ok(1), Ok(11), Ok(1426), Ok(3)]);
}
}
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰

View file

@ -1,71 +1 @@
// 3 possible solutions are presented.
// With `for` loop and a mutable variable.
fn factorial_for(num: u64) -> u64 {
let mut result = 1;
for x in 2..=num {
result *= x;
}
result
}
// Equivalent to `factorial_for` but shorter and without a `for` loop and
// mutable variables.
fn factorial_fold(num: u64) -> u64 {
// Case num==0: The iterator 2..=0 is empty
// -> The initial value of `fold` is returned which is 1.
// Case num==1: The iterator 2..=1 is also empty
// -> The initial value 1 is returned.
// Case num==2: The iterator 2..=2 contains one element
// -> The initial value 1 is multiplied by 2 and the result
// is returned.
// Case num==3: The iterator 2..=3 contains 2 elements
// -> 1 * 2 is calculated, then the result 2 is multiplied by
// the second element 3 so the result 6 is returned.
// And so on…
(2..=num).fold(1, |acc, x| acc * x)
}
// Equivalent to `factorial_fold` but with a built-in method that is suggested
// by Clippy.
fn factorial_product(num: u64) -> u64 {
(2..=num).product()
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn factorial_of_0() {
assert_eq!(factorial_for(0), 1);
assert_eq!(factorial_fold(0), 1);
assert_eq!(factorial_product(0), 1);
}
#[test]
fn factorial_of_1() {
assert_eq!(factorial_for(1), 1);
assert_eq!(factorial_fold(1), 1);
assert_eq!(factorial_product(1), 1);
}
#[test]
fn factorial_of_2() {
assert_eq!(factorial_for(2), 2);
assert_eq!(factorial_fold(2), 2);
assert_eq!(factorial_product(2), 2);
}
#[test]
fn factorial_of_4() {
assert_eq!(factorial_for(4), 24);
assert_eq!(factorial_fold(4), 24);
assert_eq!(factorial_product(4), 24);
}
}
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰

View file

@ -1,150 +1 @@
// Let's define a simple model to track Rustlings' exercise progress. Progress
// will be modelled using a hash map. The name of the exercise is the key and
// the progress is the value. Two counting functions were created to count the
// number of exercises with a given progress. Recreate this counting
// functionality using iterators. Try to not use imperative loops (for/while).
use std::collections::HashMap;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Progress {
None,
Some,
Complete,
}
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
let mut count = 0;
for val in map.values() {
if *val == value {
count += 1;
}
}
count
}
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
// `map` is a hash map with `String` keys and `Progress` values.
// map = { "variables1": Complete, "from_str": None, … }
map.values().filter(|val| **val == value).count()
}
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
let mut count = 0;
for map in collection {
count += count_for(map, value);
}
count
}
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
// `collection` is a slice of hash maps.
// collection = [{ "variables1": Complete, "from_str": None, … },
// { "variables2": Complete, … }, … ]
collection
.iter()
.map(|map| count_iterator(map, value))
.sum()
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
fn get_map() -> HashMap<String, Progress> {
use Progress::*;
let mut map = HashMap::new();
map.insert(String::from("variables1"), Complete);
map.insert(String::from("functions1"), Complete);
map.insert(String::from("hashmap1"), Complete);
map.insert(String::from("arc1"), Some);
map.insert(String::from("as_ref_mut"), None);
map.insert(String::from("from_str"), None);
map
}
fn get_vec_map() -> Vec<HashMap<String, Progress>> {
use Progress::*;
let map = get_map();
let mut other = HashMap::new();
other.insert(String::from("variables2"), Complete);
other.insert(String::from("functions2"), Complete);
other.insert(String::from("if1"), Complete);
other.insert(String::from("from_into"), None);
other.insert(String::from("try_from_into"), None);
vec![map, other]
}
#[test]
fn count_complete() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::Complete), 3);
}
#[test]
fn count_some() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::Some), 1);
}
#[test]
fn count_none() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::None), 2);
}
#[test]
fn count_complete_equals_for() {
let map = get_map();
let progress_states = [Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_for(&map, progress_state),
count_iterator(&map, progress_state),
);
}
}
#[test]
fn count_collection_complete() {
let collection = get_vec_map();
assert_eq!(
count_collection_iterator(&collection, Progress::Complete),
6,
);
}
#[test]
fn count_collection_some() {
let collection = get_vec_map();
assert_eq!(count_collection_iterator(&collection, Progress::Some), 1);
}
#[test]
fn count_collection_none() {
let collection = get_vec_map();
assert_eq!(count_collection_iterator(&collection, Progress::None), 4);
}
#[test]
fn count_collection_equals_for() {
let collection = get_vec_map();
let progress_states = [Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_collection_for(&collection, progress_state),
count_collection_iterator(&collection, progress_state),
);
}
}
}
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰

View file

@ -1,47 +1 @@
// At compile time, Rust needs to know how much space a type takes up. This
// becomes problematic for recursive types, where a value can have as part of
// itself another value of the same type. To get around the issue, we can use a
// `Box` - a smart pointer used to store data on the heap, which also allows us
// to wrap a recursive type.
//
// The recursive type we're implementing in this exercise is the "cons list", a
// data structure frequently found in functional programming languages. Each
// item in a cons list contains two elements: The value of the current item and
// the next item. The last item is a value called `Nil`.
#[derive(PartialEq, Debug)]
enum List {
Cons(i32, Box<List>),
Nil,
}
fn create_empty_list() -> List {
List::Nil
}
fn create_non_empty_list() -> List {
List::Cons(42, Box::new(List::Nil))
}
fn main() {
println!("This is an empty cons list: {:?}", create_empty_list());
println!(
"This is a non-empty cons list: {:?}",
create_non_empty_list(),
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_empty_list() {
assert_eq!(create_empty_list(), List::Nil);
}
#[test]
fn test_create_non_empty_list() {
assert_ne!(create_empty_list(), create_non_empty_list());
}
}
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰