Hello rustafarians, I hope some of you might help review this code on finding saddle points. I go over the instructions, summarize my solution, and provide code. I include the code I write as `src/lib.rs`

and the tests Exercism provides as `tests/saddle-points.rs`

.

As is it passes all tests, and I am looking for suggestions to improve / refactor the already functional code. Any and all suggestions welcome, thanks for checking this out!

This is from an exercise on exercism.io, and the instructions define a saddle point as one which

- is >= every element in row
- is <= every element in column

**The Instructions**

The goal is to produce the saddle points of a given 2D vector from this function, which has a predetermined parameter and output. Any other functions may also be used, but these parameters may not be changed.

```
pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {}
```

**My Solution**

Here is my approach:

- Turn the input from a 2D array of
`Vec`

s (I think that is what`&[Vec<u64>]`

is) into a 1D`Vec`

. - Use a helper function to find the minimum values per column and the maximum values per row.
- Loop through 1D
`Vec`

and`push`

to output all values which are`==`

to their row's max and`==`

their column's min.

**My Code**

src/lib.rs

```
// Find saddle points in a given 2d vector.
// Changes 2D vector input to 1D vector,
// finds max row values and min col values and puts in new vector,
// compares values in 1D vector to find saddle points.
// Questions for later:
// - Any way to reduce number of times vectors are made?
// - Is this more efficient than making another 2D vector by rotating?
// - Many `for` loops here, should any be replaced by iterators or
// `while let` statements or something?
pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
let mut saddles: Vec<(usize, usize)> = Vec::new();
// Early return if input is empty
if input[0].len() == 0 || input.len() == 0 {
return saddles;
}
let y_len = input.len();
let x_len = input[0].len();
let one_d_vec = two_d_to_one_d(input, y_len * x_len);
let (max_row_vals, min_col_vals) = max_rows_min_cols(one_d_vec, x_len, y_len);
for y_pos in 0..y_len {
for x_pos in 0..x_len {
let current_num = input[y_pos][x_pos];
if current_num == max_row_vals[y_pos] && current_num == min_col_vals[x_pos] {
saddles.push((y_pos, x_pos));
}
}
}
saddles
}
// Changes 2D input vector to 1D output vector
pub fn two_d_to_one_d(input: &[Vec<u64>], capacity: usize) -> Vec<u64> {
let mut one_d_vec: Vec<u64> = Vec::with_capacity(capacity);
for row in input {
for num in row {
one_d_vec.push(*num);
}
}
one_d_vec
}
// Takes 1D input vector, finds max row values and min col values
fn max_rows_min_cols(one_d_vec: Vec<u64>, x_len: usize, y_len: usize) -> (Vec<u64>, Vec<u64>) {
let mut min_col_vals: Vec<u64> = Vec::with_capacity(x_len);
let mut max_row_vals: Vec<u64> = Vec::with_capacity(y_len);
// Initializing min_col_vals. No need w/ max_row_vals.
for _ in 0..x_len {
min_col_vals.push(u64::max_value())
}
// Iterate through each value in vec to find mins and maxes.
let mut max_x = u64::min_value();
for (i, num) in one_d_vec.iter().enumerate() {
// Getting min values in each column and insert/removing from vec
for row in 0..x_len {
if (i % x_len) == row && *num <= min_col_vals[row] {
let _ = min_col_vals.remove(row);
min_col_vals.insert(row, *num);
}
}
// Getting max values in each row and pushing to vec
for _col in 0..x_len {
if *num >= max_x {
max_x = *num;
}
}
if (i + 1) % x_len == 0 {
max_row_vals.push(max_x);
max_x = u64::min_value();
}
}
(max_row_vals, min_col_vals)
}
```

**Tests**

tests/saddle-points.rs

```
use saddle_points;
use saddle_points::find_saddle_points;
// We don't care about order
fn find_sorted_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
let mut result = saddle_points::find_saddle_points(input);
result.sort();
result
}
#[test]
fn identify_single_saddle_point() {
// 9, 8, 7
// 5, 3, 2
// 6, 6, 7
let input = vec![vec![9, 8, 7], vec![5, 3, 2], vec![6, 6, 7]];
assert_eq!(vec![(1, 0)], find_saddle_points(&input));
}
#[test]
#[ignore]
fn identify_empty_matrix() {
let input = vec![vec![], vec![], vec![]];
let expected: Vec<(usize, usize)> = Vec::new();
assert_eq!(expected, find_saddle_points(&input));
}
#[test]
#[ignore]
fn identify_lack_of_saddle_point() {
let input = vec![vec![1, 2, 3], vec![3, 1, 2], vec![2, 3, 1]];
let expected: Vec<(usize, usize)> = Vec::new();
assert_eq!(expected, find_saddle_points(&input));
}
#[test]
#[ignore]
fn multiple_saddle_points_in_col() {
let input = vec![vec![4, 5, 4], vec![3, 5, 5], vec![1, 5, 4]];
assert_eq!(
vec![(0, 1), (1, 1), (2, 1)],
find_sorted_saddle_points(&input)
);
}
#[test]
#[ignore]
fn multiple_saddle_points_in_row() {
let input = vec![vec![6, 7, 8], vec![5, 5, 5], vec![7, 5, 6]];
assert_eq!(
vec![(1, 0), (1, 1), (1, 2)],
find_sorted_saddle_points(&input)
);
}
#[test]
#[ignore]
fn identify_bottom_right_saddle_point() {
let input = vec![vec![8, 7, 9], vec![6, 7, 6], vec![3, 2, 5]];
assert_eq!(vec![(2, 2)], find_saddle_points(&input));
}
// track specific as of v1.3
#[test]
#[ignore]
fn non_square_matrix_high() {
let input = vec![vec![1, 5], vec![3, 6], vec![2, 7], vec![3, 8]];
assert_eq!(vec![(0, 1)], find_saddle_points(&input));
}
#[test]
#[ignore]
fn non_square_matrix_wide() {
let input = vec![vec![3, 1, 3], vec![3, 2, 4]];
assert_eq!(vec![(0, 0), (0, 2)], find_sorted_saddle_points(&input));
}
#[test]
#[ignore]
fn single_column_matrix() {
let input = vec![vec![2], vec![1], vec![4], vec![1]];
assert_eq!(vec![(1, 0), (3, 0)], find_sorted_saddle_points(&input));
}
#[test]
#[ignore]
fn single_row_matrix() {
let input = vec![vec![2, 5, 3, 5]];
assert_eq!(vec![(0, 1), (0, 3)], find_sorted_saddle_points(&input));
}
#[test]
#[ignore]
fn identify_all_saddle_points() {
let input = vec![vec![5, 5, 5], vec![5, 5, 5], vec![5, 5, 5]];
assert_eq!(
vec![
(0, 0),
(0, 1),
(0, 2),
(1, 0),
(1, 1),
(1, 2),
(2, 0),
(2, 1),
(2, 2)
],
find_sorted_saddle_points(&input)
);
}
```