diff --git a/practical.yml b/practical.yml index 2988374..3862b74 100644 --- a/practical.yml +++ b/practical.yml @@ -44,3 +44,8 @@ exercises: tests: - "add_last_two_not_enough" - "add_last_two_enough" + - "dup_top_empty" + - "dup_top_has_value" + - "median_already_sorted" + - "median_shuffled" + - "median_empty" diff --git a/subject_source/src/vec/access.rs b/subject_source/src/vec/access.rs index 16ab63a..2b12258 100644 --- a/subject_source/src/vec/access.rs +++ b/subject_source/src/vec/access.rs @@ -1,10 +1,37 @@ /// Add the last two numbers of the input slice. /// -/// If the slice is not large enough, return `None` -/// If it is, return the computed value in a `Some` +/// # Return value +/// `None` if the slice is not large enough +/// `Some(result)` if the slice has at least 2 elements pub fn add_last_two(v: &[f32]) -> Option { match v.last_chunk() { Some([a, b]) => Some(a + b), None => None, } } + +/// Duplicate the top element from the stack if it exist +/// (the stack is represented as a Vec with top == last) +/// +/// # Return value +/// `Some(())` if the operation succeeded +/// `None` if not +pub fn dup_top(v: &mut Vec) -> Option<()> { + match v.last() { + Some(last) => { + v.push(*last); + return Some(()); + } + _ => return None, + } +} + +/// Compute the median of a slice in place (if the slice was sorted, it would be the middle element) +pub fn median(v: &[i32]) -> Option { + let mut tmp = v.to_vec(); + tmp.sort(); + match tmp.get(tmp.len() / 2) { + Some(&r) => Some(r), + None => None, + } +} diff --git a/subject_source/tests/vec_access.rs b/subject_source/tests/vec_access.rs index 376a2ee..8096fdb 100644 --- a/subject_source/tests/vec_access.rs +++ b/subject_source/tests/vec_access.rs @@ -9,3 +9,31 @@ pub fn add_last_two_not_enough() { pub fn add_last_two_enough() { assert_eq!(access::add_last_two(&[1.0, 2.0, 3.0]), Some(5.0)); } + +#[test] +pub fn dup_top_empty() { + let mut empty = vec![]; + assert!(access::dup_top(&mut empty).is_none()); +} + +#[test] +pub fn dup_top_has_values() { + let mut empty = vec![1.0, 2.0]; + assert!(access::dup_top(&mut empty).is_some()); + assert_eq!(empty, &[1.0, 2.0, 2.0]); +} + +#[test] +pub fn median_already_sorted() { + assert_eq!(access::median(&[1, 2, 3]), Some(2)); +} + +#[test] +pub fn median_shuffled() { + assert_eq!(access::median(&[420, 69, 128]), Some(128)); +} + +#[test] +pub fn median_empty() { + assert_eq!(access::median(&[]), None); +} diff --git a/subject_text/vec/access.md b/subject_text/vec/access.md new file mode 100644 index 0000000..e782b1c --- /dev/null +++ b/subject_text/vec/access.md @@ -0,0 +1,60 @@ +--- +name = "Accessing values" +file = "src/vec/access.rs" +--- + +Instead of using the good old C-style bound checking: + +```rust +if vec.len() < 1 { + return None; +} else { + // compiler still thinks this line can panic + return vec[0]; +} +``` + +Try to implement these functions using non-panicking methods like [`last`](https://doc.rust-lang.org/std/primitive.slice.html#method.last), [`last_chunk`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_chunk), or [`get`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). + +```prototype +/// Add the last two numbers of the input slice. +/// +/// # Return value +/// `None` if the slice is not large enough +/// `Some(result)` if the slice has at least 2 elements +pub fn add_last_two(v: &[f32]) -> Option { + unimplemented!() +} + +/// Duplicate the top element from the stack if it exist +/// (the stack is represented as a Vec with top == last) +/// +/// # Return value +/// `Some(())` if the operation succeeded +/// `None` if not +pub fn dup_top(v: &mut Vec) -> Option<()> { + unimplemented!() +} + +/// Compute the median of a slice in place (if the slice was sorted, it would be the middle element) +pub fn median(v: &[i32]) -> Option { + unimplemented!() +} +``` + +```example +fn main() { + assert_eq!(add_last_two(&[]), None); + assert_eq!(add_last_two(&[10.0]), None); + assert_eq!(add_last_two(&[1.0, 2.0, 3.0]), Some(5.0)); + + let mut stack = vec![1.0]; + assert!(dup_top(&mut stack).is_some()); + assert_eq!(&stack, &[1.0, 1.0]); + + stack.clear(); + assert!(dup_top(&mut stack).is_none()); + + assert_eq!(median(&[2, 1, 3]), Some(2)); +} +``` diff --git a/subject_text/vec/index.md b/subject_text/vec/index.md index af20326..f30862f 100644 --- a/subject_text/vec/index.md +++ b/subject_text/vec/index.md @@ -14,21 +14,3 @@ Slices (`[T]`) represent some memory space containing an arbitrary number of ele `Vec` can be seen as [owned](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html) `[T]`, it means that every function working on a `&[T]` can work on a `&Vec`. ``` -```prototype -/// Add the last two numbers of the input slice. -/// -/// If the slice is not large enough, return `None` -/// If it is, return the computed value in a `Some` -pub fn add_last_two(v: &[f32]) -> Option { - unimplemented!() -} -``` - -```example -fn main() { - assert_eq!(add_last_two(&[]), None); - assert_eq!(add_last_two(&[10.0]), None); - assert_eq!(add_last_two(&[1.0, 2.0, 3.0]), Some(5.0)); -} -``` -