Compare commits
4 Commits
c52caca844
...
2ddc195b73
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ddc195b73 | |||
| cd8ee2ba72 | |||
| c741e49e78 | |||
| 1b850fc73e |
@ -44,3 +44,18 @@ exercises:
|
|||||||
tests:
|
tests:
|
||||||
- "add_last_two_not_enough"
|
- "add_last_two_not_enough"
|
||||||
- "add_last_two_enough"
|
- "add_last_two_enough"
|
||||||
|
- "dup_top_empty"
|
||||||
|
- "dup_top_has_value"
|
||||||
|
- "median_already_sorted"
|
||||||
|
- "median_shuffled"
|
||||||
|
- "median_empty"
|
||||||
|
compute:
|
||||||
|
required_files:
|
||||||
|
- "src/vec.rs"
|
||||||
|
- "src/vec/compute.rs"
|
||||||
|
tests:
|
||||||
|
- "compute_empty"
|
||||||
|
- "compute_too_many_ops"
|
||||||
|
- "compute_division_by_zero_push"
|
||||||
|
- "compute_division_by_zero_operation"
|
||||||
|
- "compute_all_ops"
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
pub mod access;
|
pub mod access;
|
||||||
|
pub mod compute;
|
||||||
|
|||||||
@ -1,10 +1,37 @@
|
|||||||
/// Add the last two numbers of the input slice.
|
/// Add the last two numbers of the input slice.
|
||||||
///
|
///
|
||||||
/// If the slice is not large enough, return `None`
|
/// # Return value
|
||||||
/// If it is, return the computed value in a `Some`
|
/// `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<f32> {
|
pub fn add_last_two(v: &[f32]) -> Option<f32> {
|
||||||
match v.last_chunk() {
|
match v.last_chunk() {
|
||||||
Some([a, b]) => Some(a + b),
|
Some([a, b]) => Some(a + b),
|
||||||
None => None,
|
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<f32>) -> 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<i32> {
|
||||||
|
let mut tmp = v.to_vec();
|
||||||
|
tmp.sort();
|
||||||
|
match tmp.get(tmp.len() / 2) {
|
||||||
|
Some(&r) => Some(r),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
48
subject_source/src/vec/compute.rs
Normal file
48
subject_source/src/vec/compute.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
pub enum Operation {
|
||||||
|
Push(f32),
|
||||||
|
Binary(Binary),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Binary {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum ComputeError {
|
||||||
|
NotEnoughData,
|
||||||
|
DivisionByZero,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute(operations: &[Operation]) -> Result<f32, ComputeError> {
|
||||||
|
let mut stack = vec![];
|
||||||
|
for operation in operations {
|
||||||
|
match operation {
|
||||||
|
Operation::Push(n) => stack.push(*n),
|
||||||
|
Operation::Binary(op) => {
|
||||||
|
let b = stack.pop();
|
||||||
|
let a = stack.pop();
|
||||||
|
|
||||||
|
let r = match (a, b) {
|
||||||
|
(Some(a), Some(b)) => match op {
|
||||||
|
Binary::Add => a + b,
|
||||||
|
Binary::Mul => a * b,
|
||||||
|
Binary::Div => {
|
||||||
|
if b == 0.0 {
|
||||||
|
return Err(ComputeError::DivisionByZero);
|
||||||
|
}
|
||||||
|
a / b
|
||||||
|
}
|
||||||
|
Binary::Sub => a - b,
|
||||||
|
},
|
||||||
|
_ => return Err(ComputeError::NotEnoughData),
|
||||||
|
};
|
||||||
|
stack.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.pop().ok_or(ComputeError::NotEnoughData)
|
||||||
|
}
|
||||||
@ -9,3 +9,31 @@ pub fn add_last_two_not_enough() {
|
|||||||
pub fn add_last_two_enough() {
|
pub fn add_last_two_enough() {
|
||||||
assert_eq!(access::add_last_two(&[1.0, 2.0, 3.0]), Some(5.0));
|
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);
|
||||||
|
}
|
||||||
|
|||||||
58
subject_source/tests/vec_compute.rs
Normal file
58
subject_source/tests/vec_compute.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use subject_source::vec::compute::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn compute_empty() {
|
||||||
|
assert_eq!(compute(&[]), Err(ComputeError::NotEnoughData));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn compute_too_many_ops() {
|
||||||
|
assert_eq!(
|
||||||
|
compute(&[Operation::Push(1.0), Operation::Binary(Binary::Add)]),
|
||||||
|
Err(ComputeError::NotEnoughData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn compute_division_by_zero_push() {
|
||||||
|
assert_eq!(
|
||||||
|
compute(&[
|
||||||
|
Operation::Push(1.0),
|
||||||
|
Operation::Push(0.0),
|
||||||
|
Operation::Binary(Binary::Div)
|
||||||
|
]),
|
||||||
|
Err(ComputeError::DivisionByZero)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn compute_division_by_zero_operation() {
|
||||||
|
assert_eq!(
|
||||||
|
compute(&[
|
||||||
|
Operation::Push(1.0),
|
||||||
|
Operation::Push(1.0),
|
||||||
|
Operation::Push(1.0),
|
||||||
|
Operation::Binary(Binary::Sub),
|
||||||
|
Operation::Binary(Binary::Div)
|
||||||
|
]),
|
||||||
|
Err(ComputeError::DivisionByZero)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn compute_all_ops() {
|
||||||
|
assert_eq!(
|
||||||
|
compute(&[
|
||||||
|
Operation::Push(1.0),
|
||||||
|
Operation::Push(3.0),
|
||||||
|
Operation::Push(2.0),
|
||||||
|
Operation::Binary(Binary::Sub),
|
||||||
|
Operation::Push(5.0),
|
||||||
|
Operation::Binary(Binary::Mul),
|
||||||
|
Operation::Binary(Binary::Add),
|
||||||
|
Operation::Push(2.0),
|
||||||
|
Operation::Binary(Binary::Div),
|
||||||
|
]),
|
||||||
|
Ok(3.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
66
subject_text/vec/access.md
Normal file
66
subject_text/vec/access.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
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).
|
||||||
|
|
||||||
|
> ## note
|
||||||
|
> Don't be afraid of the `get` function prototype, look at the examples, they are fairly simple, it's just that `get` can work on multiple types, allowing for slice indexing as well as single element indexing.
|
||||||
|
|
||||||
|
> ## note
|
||||||
|
> You may want to look at the [`sort`](https://doc.rust-lang.org/std/primitive.slice.html#method.sort) and [`to_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.to_vec) functions for the median.
|
||||||
|
|
||||||
|
```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<f32> {
|
||||||
|
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<f32>) -> 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<i32> {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -6,29 +6,8 @@ exercises = ["access.md"]
|
|||||||
|
|
||||||
Let's now look at some functions on [`slice`](https://doc.rust-lang.org/std/primitive.slice.html)s and [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html)s. Instead of manualy checking things we will follow the type system using `Option`s and `Result`s we saw earlier.
|
Let's now look at some functions on [`slice`](https://doc.rust-lang.org/std/primitive.slice.html)s and [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html)s. Instead of manualy checking things we will follow the type system using `Option`s and `Result`s we saw earlier.
|
||||||
|
|
||||||
```note
|
> ## note
|
||||||
Slices (`[T]`) represent some memory space containing an arbitrary number of elements of type `T`. Since they don't have a size known at compilation time, we can only access them through pointers, commonly `&[T]` (references to slices).
|
> Slices (`[T]`) represent some memory space containing an arbitrary number of elements of type `T`. Since they don't have a size known at compilation time, we can only access them through pointers, commonly `&[T]` (references to slices).
|
||||||
```
|
|
||||||
|
|
||||||
```deepening
|
|
||||||
`Vec<T>` 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<T>`.
|
|
||||||
```
|
|
||||||
|
|
||||||
```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<f32> {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
> ## deepening
|
||||||
|
> `Vec<T>` 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<T>`.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user