Skip to content

Commit

Permalink
Answers for standard_library_types
Browse files Browse the repository at this point in the history
iterators4.rs was particularly instructive.

I started out by searching for the initial C recursion and for loop
versions and tried to use a range iteration but couldn't figure the
syntax. So I created the first 7 answers and then used hint.

I then seached for: how to use iterator for side effects only
 https://www.google.com/search?q=how+to+use+iterator+for+side+effects+only+in+rust

And saw this:
 rust-lang/rust#44546 (comment)
And:
 rust-lang/rust#44546 (comment)

And with that I implemented Answer 8

But still wasn't happy as I felt there must be a better way where I didn't
need to throw away things. So I looking at the iterator documentation:
 https://doc.rust-lang.org/std/iter/trait.Iterator.html

I saw "fold" and low and behold that was exactly what I needed! Then I
saw "fold_first" and it was "simpler" as the first value in the range
is the initial value for the accumulator so fold_first only has one
parameters not two. But fold_first returns an Option which means I need
to return the unwrap(). Anyway both Answers 9 and 10 are simpler then
any other solution!

I do wonder which is fastest.
  • Loading branch information
winksaville committed Dec 16, 2020
1 parent 8bab9fe commit b58936a
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 25 deletions.
27 changes: 24 additions & 3 deletions exercises/standard_library_types/arc1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
// somewhere. Try not to create any copies of the `numbers` Vec!
// Execute `rustlings hint arc1` for hints :)

// I AM NOT DONE
// I AM DONE

#![forbid(unused_imports)] // Do not change this, (or the next) line.
use std::sync::Arc;
use std::thread;

fn main() {
let numbers: Vec<_> = (0..100u32).collect();
let shared_numbers = // TODO
let numbers: Vec<_> = (0..100u64).collect();
let shared_numbers = Arc::new(numbers);
let mut joinhandles = Vec::new();

// Answer 1
for offset in 0..8 {
let child_numbers = shared_numbers.clone();
joinhandles.push(thread::spawn(move || {
let mut i = offset;
let mut sum = 0;
Expand All @@ -26,6 +28,25 @@ fn main() {
println!("Sum of offset {} is {}", offset, sum);
}));
}

//// Answer 2
//let threads = 10;
//let shard_size = shared_numbers.len() / threads;
//if shared_numbers.len() % threads != 0 {
// panic!("shard_size isn't a multiple of numbers.len");
//}
//for offset in 0..threads {
// let child_numbers = shared_numbers.clone();
// joinhandles.push(thread::spawn(move || {
// let base = shard_size * offset;
// let mut sum = 0;
// for i in 0..shard_size {
// sum += child_numbers[base + i];
// }
// println!("Sum of offset {} is {}", offset, sum);
// }));
//}

for handle in joinhandles.into_iter() {
handle.join().unwrap();
}
Expand Down
9 changes: 5 additions & 4 deletions exercises/standard_library_types/box1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
//
// Execute `rustlings hint box1` for hints :)

// I AM NOT DONE
// I AM DONE

#[derive(PartialEq, Debug)]
pub enum List {
Cons(i32, List),
Cons(i32, Box<List>),
Nil,
}

Expand All @@ -33,11 +33,12 @@ fn main() {
}

pub fn create_empty_list() -> List {
unimplemented!()
List::Nil
}

pub fn create_non_empty_list() -> List {
unimplemented!()
//List::Cons(1, Box::new(List::Nil))
List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))))
}

#[cfg(test)]
Expand Down
12 changes: 7 additions & 5 deletions exercises/standard_library_types/iterators1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
//
// Execute `rustlings hint iterators1` for hints :D

// I AM NOT DONE
// I AM DONE

fn main () {
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];

let mut my_iterable_fav_fruits = ???; // TODO: Step 1
let mut my_iterable_fav_fruits = my_fav_fruits.iter(); // TODO: Step 1

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(&"custard apple")); // TODO: Step 2
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1
assert_eq!(my_iterable_fav_fruits.next(), Some(&"peach")); // TODO: Step 2.1
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
assert_eq!(my_iterable_fav_fruits.next(), None); // TODO: Step 3
// iterator next() continues to return no
assert_eq!(my_iterable_fav_fruits.next(), None); // TODO: Step 3
}
12 changes: 8 additions & 4 deletions exercises/standard_library_types/iterators2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
// Try to ensure it returns a single string.
// As always, there are hints if you execute `rustlings hint iterators2`!

// I AM NOT DONE
// I AM DONE

pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => first.collect::<String>() + c.as_str(),
Some(first) => first.to_uppercase().collect::<String>() + c.as_str(),
}
}

pub fn capitalize_words(input: Vec<&str>) -> Vec<String> {
input.iter().map(|w| { capitalize_first(w) }).collect()
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -37,14 +41,14 @@ mod tests {
#[test]
fn test_iterate_string_vec() {
let words = vec!["hello", "world"];
let capitalized_words: Vec<String> = // TODO
let capitalized_words: Vec<String> = capitalize_words(words);
assert_eq!(capitalized_words, ["Hello", "World"]);
}

#[test]
fn test_iterate_into_string() {
let words = vec!["hello", " ", "world"];
let capitalized_words = // TODO
let capitalized_words: String = capitalize_words(words).join("");
assert_eq!(capitalized_words, "Hello World");
}
}
22 changes: 14 additions & 8 deletions exercises/standard_library_types/iterators3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// Execute `rustlings hint iterators3` to get some hints!
// Have fun :-)

// I AM NOT DONE
// I AM DONE

#[derive(Debug, PartialEq, Eq)]
pub enum DivisionError {
Expand All @@ -24,7 +24,15 @@ pub struct NotDivisibleError {
// This function should calculate `a` divided by `b` if `a` is
// evenly divisible by b.
// Otherwise, it should return a suitable error.
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {}
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
if b == 0 {
return Err(DivisionError::DivideByZero);
}
if (a % b) != 0 {
return Err(DivisionError::NotDivisible(NotDivisibleError {dividend: a, divisor: b}));
}
Ok(a / b)
}

#[cfg(test)]
mod tests {
Expand All @@ -46,7 +54,6 @@ mod tests {
}))
);
}

#[test]
fn test_divide_by_0() {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
Expand All @@ -56,23 +63,22 @@ mod tests {
fn test_divide_0_by_something() {
assert_eq!(divide(0, 81), Ok(0));
}

// Iterator exercises using your `divide` function
/*

#[test]
fn result_with_list() {
let numbers = vec![27, 297, 38502, 81];
//let division_results = numbers.into_iter().map(|n| divide(n, 27)).collect::<Result<i32, DivisionError>>();
let division_results = numbers.into_iter().map(|n| divide(n, 27));
let x //... Fill in here!
let x: Result<Vec<i32>, _> = division_results.collect(); //... Fill in here!
assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])");
}

#[test]
fn list_of_results() {
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
let x //... Fill in here!
let x: Vec<Result<i32, _>> = division_results.collect();
assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]");
}
*/
}
176 changes: 175 additions & 1 deletion exercises/standard_library_types/iterators4.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,147 @@
#![feature(iterator_fold_self)]
// iterators4.rs

// I AM NOT DONE
// I AM DONE

pub fn recursive(num: u64) -> u64 {
let mut fact = num;
if num > 1 {
fact = num * recursive(num - 1)
}
println!("recursive: num={} fact={}", num, fact);
fact
}

pub fn simplest_recursive(num: u64) -> u64 {
if num > 1 {
num * simplest_recursive(num - 1)
} else {
num
}
}

pub fn match_recursive(num: u64) -> u64 {
match num {
n if n > 1 => n * match_recursive(n - 1),
n => n,
}
}

pub fn for_in(num: u64) -> u64 {
let mut fact = 1;
for i in 1..num+1 {
fact *= i;
println!("for_in: num={} fact={}", num, fact);
}
fact
}

// Create iterable version of Factorial

struct Factorial {
num: u64,
factorial: u64,
}

impl Factorial {
fn new(num: u64) -> Factorial {
Factorial {
num,
factorial: 1
}
}
}

impl Iterator for Factorial {
type Item = u64;

fn next(&mut self) -> Option<Self::Item> {
println!("Factorial::next:+ self.num={}", self.num);
if self.num > 0 {
self.factorial *= self.num;
self.num -= 1;
println!("Factorial::next:- Some self.factorial={}", self.factorial);
return Some(self.factorial)
} else {
println!("Factorial::next:- None self.factorial={}", self.factorial);
return None
}
}
}

pub fn loop_next_iterator(num: u64) -> u64 {
let mut f = Factorial::new(num);
loop {
let n = f.next();
if n == None {
break;
}
println!("iterator: f.next()={}", n.unwrap());
}
println!("iterator:- f.factorial={}", f.factorial);
f.factorial
}

pub fn for_in_iterator(num: u64) -> u64 {
println!("iterator:+ num={}", num);
let f = Factorial::new(num);
let mut x: u64 = 1;
for curf in f {
println!("iterator: curf={}", curf);
x = curf;
}
println!("iterator:- x={}", x);
x
}

pub fn while_next_iterator(num: u64) -> u64 {
let mut f = Factorial::new(num);
while f.next() != None {}
f.factorial
}

pub fn range_for_each_iterator(num: u64) -> u64 {
// "rf" is a a reference to mutable fact
// which is captured by the map closure.
//let mut fact: u64 = 1;
//let rf = &mut fact;
//(1..num+1).map(|n| {
// *rf *= n;
// println!("n={} *rf={}", n, *rf);
//} ).for_each(drop);
//fact

// Turns out you don't need "rf", I'm guessing because fact
// is on the left side of "=" and therfore is areference.
let mut fact: u64 = 1;
(1..num+1).map(|n| {
fact *= n;
//println!("n={} fact={}", n, fact);
} ).for_each(drop);
fact
}

pub fn range_fold_iterator(num: u64) -> u64 {
(1..num+1).fold(1, |fact, n| fact * n)

//// For debugging add a println
//(1..num+1).fold(1, |fact, n| {
// let f = fact * n;
// println!("n={} f={}", n, f);
// f
//} )
}

pub fn range_fold_first_iterator(num: u64) -> u64 {
(1..num+1).fold_first(|fact, n| fact * n).unwrap()

//// For debugging add a println
//(1..num+1).fold_first(|fact, n| {
// let f = fact * n;
// println!("n={} f={}", n, f);
// f
//} ).unwrap()
}

pub fn factorial(num: u64) -> u64 {
// Complete this function to return the factorial of num
Expand All @@ -12,7 +153,40 @@ pub fn factorial(num: u64) -> u64 {
// For an extra challenge, don't use:
// - recursion
// Execute `rustlings hint iterators4` for hints.

// Answer 1 recursive
//recursive(num)

// Answer 2 simplest recursive
//simplest_recursive(num)

// Answer 3 match recursive
//match_recursive(num)

// Answer 4 for_in no recursion
//for_in(num)

// Answer 5 iterate using loop
//loop_next_iterator(num)

// Answer 6 iterate using for in
//for_in_iterator(num)

// Answer 7 iterate using while
//while_next_iterator(num)

// Answer 8 Iterate using range and for_each
//range_for_each_iterator(num)

// Answer 9 Iterate using range and fold
// THIS IS THE BEST ANSWER, or maybe fold_first below.
//range_fold_iterator(num)

// Answer 10 Iterate using range and fold_first
// THIS IS THE BEST ANSWER :)
range_fold_first_iterator(num)
}


#[cfg(test)]
mod tests {
Expand Down

0 comments on commit b58936a

Please sign in to comment.