python saddle points

This commit is contained in:
Xevion
2020-11-15 09:24:53 -06:00
parent 54e9dba5fc
commit 7237f622d7
4 changed files with 177 additions and 0 deletions

View File

@@ -0,0 +1 @@
{"track":"python","exercise":"saddle-points","id":"142ada3a5e35437baa24b9bddb78a991","url":"https://exercism.io/my/solutions/142ada3a5e35437baa24b9bddb78a991","handle":"Xevion","is_requester":true,"auto_approve":false}

View File

@@ -0,0 +1,76 @@
# Saddle Points
Detect saddle points in a matrix.
So say you have a matrix like so:
```text
1 2 3
|---------
1 | 9 8 7
2 | 5 3 2 <--- saddle point at (2,1)
3 | 6 6 7
```
It has a saddle point at (2, 1).
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.
## Exception messages
Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to
indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. Not
every exercise will require you to raise an exception, but for those that do, the tests will only pass if you include
a message.
To raise a message with an exception, just write it as an argument to the exception type. For example, instead of
`raise Exception`, you should write:
```python
raise Exception("Meaningful message indicating the source of the error")
```
## Running the tests
To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)):
- Python 2.7: `py.test saddle_points_test.py`
- Python 3.4+: `pytest saddle_points_test.py`
Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version):
`python -m pytest saddle_points_test.py`
### Common `pytest` options
- `-v` : enable verbose output
- `-x` : stop running tests on first failure
- `--ff` : run failures from previous test before running other test cases
For other options, see `python -m pytest -h`
## Submitting Exercises
Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/saddle-points` directory.
You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`.
For more detailed information about running tests, code style and linting,
please see [Running the Tests](http://exercism.io/tracks/python/tests).
## 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.

View File

@@ -0,0 +1,18 @@
def saddle_points(matrix):
# Check a single point in the matrix for if it's a saddle point
def saddle(point):
row = matrix[point[0]]
column = [row[point[1]] for row in matrix]
return max(row) == row[point[1]] and min(column) == column[point[0]]
# Raise a value error if the matrix lengths are not consistent
if len(set(list(map(len, matrix)))) > 1:
d = {i : len(m) for i, m in enumerate(matrix)}
d = sorted(list(set(list(d.values()))), reverse=True)
raise ValueError(f'Matrix Length of {d[-1]} instead of usual {d[0]} found.')
saddles = []
# Check every point for if it's a saddle point
for x, row in enumerate(matrix):
for y, point in enumerate(row):
if saddle((x, y)):
saddles.append({'row' : x + 1, 'column' : y + 1})
return saddles or [{}]

View File

@@ -0,0 +1,82 @@
"""Tests for the saddle-points exercise
Implementation note:
The saddle_points function must validate the input matrix and raise a
ValueError with a meaningful error message if the matrix turns out to be
irregular.
"""
import unittest
from saddle_points import saddle_points
# Tests adapted from `problem-specifications//canonical-data.json` @ v1.5.0
class SaddlePointsTest(unittest.TestCase):
def test_identify_single_saddle_point(self):
matrix = [[9, 8, 7], [5, 3, 2], [6, 6, 7]]
self.assertEqual(saddle_points(matrix), [{"row": 2, "column": 1}])
def test_empty_matrix_has_no_saddle_points(self):
self.assertEqual(saddle_points([]), [dict()])
def test_matrix_with_one_elem_has_single_saddle_point(self):
matrix = [[1]]
self.assertEqual(saddle_points(matrix), [{"row": 1, "column": 1}])
def test_identify_lack_of_saddle_points_when_there_are_none(self):
matrix = [[1, 2, 3], [3, 1, 2], [2, 3, 1]]
self.assertEqual(saddle_points(matrix), [dict()])
def test_identify_multiple_saddle_points_in_column(self):
matrix = [[4, 5, 4], [3, 5, 5], [1, 5, 4]]
expected = [{"row": 1, "column": 2}, {"row": 2, "column": 2},
{"row": 3, "column": 2}]
self.assertEqual(saddle_points(matrix), expected)
def test_identify_multiple_saddle_points_in_row(self):
matrix = [[6, 7, 8], [5, 5, 5], [7, 5, 6]]
expected = [{"row": 2, "column": 1}, {"row": 2, "column": 2},
{"row": 2, "column": 3}]
self.assertEqual(saddle_points(matrix), expected)
def test_identify_saddle_point_in_bottom_right_corner(self):
matrix = [[8, 7, 9], [6, 7, 6], [3, 2, 5]]
expected = [{"row": 3, "column": 3}]
self.assertEqual(saddle_points(matrix), expected)
def test_non_square_matrix_with_2_saddle_points(self):
matrix = [[3, 1, 3], [3, 2, 4]]
self.assertEqual(saddle_points(matrix), [{"row": 1, "column": 1},
{"row": 1, "column": 3}])
def test_single_column_matrix_has_saddle_point_min_value(self):
matrix = [[2], [1], [4], [1]]
self.assertEqual(saddle_points(matrix), [{"row": 2, "column": 1},
{"row": 4, "column": 1}])
def test_single_row_matrix_has_saddle_point_in_max_value(self):
matrix = [[2, 5, 3, 5]]
self.assertEqual(saddle_points(matrix), [{"row": 1, "column": 2},
{"row": 1, "column": 4}])
# Additional tests for this track
def test_irregular_matrix(self):
matrix = [[3, 2, 1], [0, 1], [2, 1, 0]]
with self.assertRaisesWithMessage(ValueError):
saddle_points(matrix)
# Utility functions
def setUp(self):
try:
self.assertRaisesRegex
except AttributeError:
self.assertRaisesRegex = self.assertRaisesRegexp
def assertRaisesWithMessage(self, exception):
return self.assertRaisesRegex(exception, r".+")
if __name__ == '__main__':
unittest.main()