Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e04e3c0
Added tests an more README info.
hekrause Oct 17, 2017
cd20bcf
Duplicate test let CI fail.
hekrause Oct 17, 2017
d9c2e9d
Don't know why warnings are only displayed on CI.
hekrause Oct 17, 2017
6998c3e
Deny warnings on wrong place.
hekrause Oct 17, 2017
1441317
Removed tests which failed only on CI.
hekrause Oct 17, 2017
168135d
Merge branch 'master' into master
hekrause Nov 5, 2017
fce8915
Remove changes.
hekrause Nov 5, 2017
3833a54
Merge branch 'master' of https://github.com/hekrause/rust
hekrause Nov 5, 2017
20c0ab0
pascals-triangle: 1.2.0
petertseng Nov 6, 2017
834b743
pascals-triangle: move four between three and five
petertseng Nov 6, 2017
50b0d69
Merge branch 'master' of https://github.com/exercism/rust
hekrause Nov 22, 2017
72b1604
Remove duplicated tests.
hekrause Nov 25, 2017
c784f9d
Remove diffie-hellman
hekrause Nov 25, 2017
1d04e9a
Initial saddle-points commit.
hekrause Nov 25, 2017
f2c139d
Remove diffie-hellman left-overs.
hekrause Nov 25, 2017
c5e0144
Remove old README.md
hekrause Nov 25, 2017
c6fa7ff
Generate new README.md
hekrause Nov 25, 2017
bb710fc
Try only to change README.md
hekrause Nov 26, 2017
fb0f63b
Made requested changes.
hekrause Nov 29, 2017
45c002d
Change tests again.
hekrause Nov 30, 2017
b64d368
Fix merge conflict with master
coriolinus Dec 14, 2017
ab95998
Update find_saddle_points signature
coriolinus Dec 14, 2017
1f07992
Merge branch 'master' into saddle-points
coriolinus Dec 14, 2017
badcc30
Rename test `*quadratic*` -> `*square*`
coriolinus Dec 14, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@
"error handling with Result<T, E>"
]
},
{
"uuid": "ccebfa12-d224-11e7-8941-cec278b6b50a",
"slug": "saddle-points",
"core": false,
"unlocked_by": null,
"difficulty": 3,
"topics": [
"vectors",
"iterators"
]
},
{
"uuid": "79613fd8-b7da-11e7-abc4-cec278b6b50a",
"slug": "isogram",
Expand Down
8 changes: 8 additions & 0 deletions exercises/saddle-points/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Generated by Cargo
# will have compiled files and executables
/target/
**/*.rs.bk

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
5 changes: 5 additions & 0 deletions exercises/saddle-points/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "saddle-points"
version = "1.0.0"

[dependencies]
66 changes: 66 additions & 0 deletions exercises/saddle-points/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Saddle Points

Detect saddle points in a matrix.

So say you have a matrix like so:

```text
0 1 2
|---------
0 | 9 8 7
1 | 5 3 2 <--- saddle point at (1,0)
2 | 6 6 7
```

It has a saddle point at (1, 0).

It's called a "saddle point" because it is greater than or equal to
every element in its row and less than or equal to every element in
its column.

A matrix may have zero or more saddle points.

Your code should be able to provide the (possibly empty) list of all the
saddle points for any given matrix.

Note that you may find other definitions of matrix saddle points online,
but the tests for this exercise follow the above unambiguous definition.

## Rust Installation

Refer to the [exercism help page][help-page] for Rust installation and learning
resources.

## Writing the Code

Execute the tests with:

```bash
$ cargo test
```

All but the first test have been ignored. After you get the first test to
pass, remove the ignore flag (`#[ignore]`) from the next test and get the tests
to pass again. The test file is located in the `tests` directory. You can
also remove the ignore flag from all the tests to get them to run all at once
if you wish.

Make sure to read the [Modules](https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html) chapter if you
haven't already, it will help you with organizing your files.

## Feedback, Issues, Pull Requests

The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the [rust track team](https://github.com/orgs/exercism/teams/rust) are happy to help!

If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md).

[help-page]: http://exercism.io/languages/rust
[modules]: https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html
[cargo]: https://doc.rust-lang.org/book/second-edition/ch14-00-more-about-cargo.html

## Source

J Dalbey's Programming Practice problems [http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html)

## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
24 changes: 24 additions & 0 deletions exercises/saddle-points/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pub fn find_saddle_points(input: &[&[u64]]) -> Vec<(u64, u64)>{
let mut saddle_points: Vec<(u64, u64)> = Vec::new();

let width = input.len();
let height = input[0].len();

for i in 0..width {
for j in 0..height {

let column = input.iter().map(|x| x[j]).collect::<Vec<u64>>();
let row = &input[i];

let max = row.iter().max().unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is only based on row, which is only based on i and not j, it would be possible to assign it in the outer loop and not the inner one. Unless that makes the code less understandable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the matrix is empty the two for loops prevent an unwrap on row in line 13.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is only based on row, which is only based on i and not j, it would be possible to assign it in the outer loop and not the inner one. Unless that makes the code less understandable.

If the matrix is empty the two for loops prevent an unwrap on row in line 13.

Indeed, if a row is empty. In that case, I will now only optionally ask for row to be moved to the outer loop (it still can be), and agree that I was wrong to ask for this max line to be moved; it cannot be.

Copy link
Contributor Author

@hekrause hekrause Nov 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right but I would like to leave it like this because I think in the way it is now it is more readable.

let min = column.iter().min().unwrap();

let value = input[i][j];

if value >= *max && value <= *min {
saddle_points.push((i as u64, j as u64));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, we could eliminate the casts here by having the function return Vec<(usize, usize)>. I prefer that over the current version.

}
}
}
saddle_points
}
1 change: 1 addition & 0 deletions exercises/saddle-points/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn find_saddle_points(input: &[&[u64]]) -> Vec<(u64, u64)>{ unimplemented!() }
103 changes: 103 additions & 0 deletions exercises/saddle-points/tests/saddle-points.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
extern crate saddle_points;

use saddle_points::*;

#[test]
fn test_identify_single_saddle_point() {
let vector: Vec<Vec<u64>> = vec![vec![9, 8, 7],
vec![5, 3, 2],
vec![6, 6, 7]];
let input: &[&[u64]] = &[&vector[0][..],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way of forming the input slice of slices is ugly, and is my fault. I inadvertently gave you bad advice. The find_saddle_points signature should actually be pub fn find_saddle_points(_: &[Vec<u64>]) -> Vec<(u64, u64)>.

I was wrong to tell you that it should accept an &[&[u64]], because the compiler doesn't automatically dereference the inner elements into a slice; the inner elements need to remain Vec<u64>. At the same time, the outer layer should be &[_] because it is idiomatic to pass a slice reference, not to transfer ownership of a Vec.

In other words, the function signature and tests should work as in this playground example.

I apologize for the bad advice. Now please change the signature one more time to hopefully clean this up once and for all.

Copy link
Member

@coriolinus coriolinus Dec 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably the best function signature for real projects would look like this:

pub fn find_saddle_points<X, Y, T>(_: &Y) -> Vec<(usize, usize)>
where
    Y: AsRef<[X]>,
    X: AsRef<[T]>,
    T: PartialOrd,
{
    unimplemented!()
}

However, that would be an intimidating signature to require of new students. I still prefer &[Vec<u64>].

&vector[1][..],
&vector[2][..]];
assert_eq!(vec![(1,0)], find_saddle_points(input));
}

#[test]
#[ignore]
fn test_identify_empty_matrix() {
let vector: Vec<Vec<u64>> = vec![vec![],
vec![],
vec![]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..],
&vector[2][..]];
let expected: Vec<(u64, u64)> = Vec::new();

assert_eq!(expected, find_saddle_points(input));
}

#[test]
#[ignore]
fn test_identify_lack_of_saddle_point() {
let vector: Vec<Vec<u64>> = vec![vec![1, 2, 3],
vec![3, 1, 2],
vec![2, 3, 1]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..],
&vector[2][..]];
let expected: Vec<(u64, u64)> = Vec::new();
assert_eq!(expected, find_saddle_points(input));
}

#[test]
#[ignore]
fn test_multiple_saddle_point() {
let vector: Vec<Vec<u64>> = vec![vec![4, 5, 4],
vec![3, 5, 5],
vec![1, 5, 4]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..],
&vector[2][..]];
assert_eq!(vec![(0,1), (1,1), (2,1)], find_saddle_points(input));
}

#[test]
#[ignore]
fn test_identify_bottom_right_saddle_point() {
let vector: Vec<Vec<u64>> = vec![vec![8, 7, 9],
vec![6, 7, 6],
vec![3, 2, 5]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..],
&vector[2][..]];
assert_eq!(vec![(2,2)], find_saddle_points(input));
}

#[test]
#[ignore]
fn test_non_square_matrix_high() {
let vector: Vec<Vec<u64>> = vec![vec![1, 5],
vec![3, 6],
vec![2, 7],
vec![3, 8]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..],
&vector[2][..],
&vector[3][..]];
assert_eq!(vec![(0, 1)], find_saddle_points(input));
}

#[test]
#[ignore]
fn test_non_quadratic_matrix_wide() {
let vector: Vec<Vec<u64>> = vec![vec![8, 7, 10, 7, 9],
vec![8, 7, 13, 7, 9]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..]];
assert_eq!(vec![(0, 2)], find_saddle_points(input));
}

#[test]
#[ignore]
fn test_vector_matrix() {
let vector: Vec<Vec<u64>> = vec![vec![1],
vec![3],
vec![2],
vec![3]];
let input: &[&[u64]] = &[&vector[0][..],
&vector[1][..],
&vector[2][..],
&vector[3][..]];
assert_eq!(vec![(0, 0)], find_saddle_points(input));
}