Skip to content

Commit

Permalink
GH-39: add min and max methods
Browse files Browse the repository at this point in the history
  • Loading branch information
qexat committed Apr 22, 2024
1 parent 8c12c20 commit 4657176
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
44 changes: 44 additions & 0 deletions magic_list/prelude.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,50 @@ def mean(self: list[int] | list[float] | list[complex]) -> float | complex:

return sum(self) / len(self)

def min(self: list[int] | list[float]) -> int | float:
"""
Return the minimum value of the list.
.. warning:: The list must be non-empty and contain numbers.
>>> L[3, 5, 2].min()
2
>>> L["hello", "world"].min()
*- TypeError: list of str has no minimum -*
>>> list().min()
*- TypeError: empty list has no minimum -*
"""

if not self:
raise TypeError("empty list has no minimum")

if not isinstance(self.head, (int, float)): # pyright: ignore[reportUnnecessaryIsInstance]
raise TypeError(f"list of {type(self.head).__name__} has no minimum")

return min(self)

def max(self: list[int] | list[float]) -> int | float:
"""
Return the maximum value of the list.
.. warning:: The list must be non-empty and contain numbers.
>>> L[3, 5, 2].max()
2
>>> L["hello", "world"].max()
*- TypeError: list of str has no maximum -*
>>> list().max()
*- TypeError: empty list has no maximum -*
"""

if not self:
raise TypeError("empty list has no maximum")

if not isinstance(self.head, (int, float)): # pyright: ignore[reportUnnecessaryIsInstance]
raise TypeError(f"list of {type(self.head).__name__} has no maximum")

return max(self)

def fill_left(
self,
filler: _T | collections.abc.Callable[[list[_T]], _T],
Expand Down
8 changes: 8 additions & 0 deletions magic_list/prelude.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ class list[_T](collections.UserList[_T]):
def mean(self: list[complex]) -> complex: ...
@typing.overload
def mean(self) -> typing_extensions.Never: ...
@typing.overload
def min[NumberT: int | float | complex](self: list[NumberT]) -> NumberT: ...
@typing.overload
def min(self) -> typing_extensions.Never: ...
@typing.overload
def max[NumberT: int | float](self: list[NumberT]) -> NumberT: ...
@typing.overload
def max(self) -> typing_extensions.Never: ...
# *- expansion-based HOFs -* #
@typing.overload
def fill_left(self, filler: _T, n: int) -> typing_extensions.Self: ...
Expand Down
50 changes: 50 additions & 0 deletions tests/list_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,56 @@ def test_sum_err(prebuild_list, exception, message):
prebuild_list.sum()


@pytest.mark.parametrize(
["prebuild_list", "result"],
[
["list_int_filled", -1],
["list_one_int", 42],
],
indirect=["prebuild_list"],
)
def test_min_ok(prebuild_list, result):
assert prebuild_list.min() == result


@pytest.mark.parametrize(
["prebuild_list", "exception", "message"],
[
["list_str_filled", TypeError, "list of str has no minimum"],
["list_empty", TypeError, "empty list has no minimum"],
],
indirect=["prebuild_list"],
)
def test_min_err(prebuild_list, exception, message):
with pytest.raises(exception, match=message):
prebuild_list.min()


@pytest.mark.parametrize(
["prebuild_list", "result"],
[
["list_int_filled", 20],
["list_one_int", 42],
],
indirect=["prebuild_list"],
)
def test_max_ok(prebuild_list, result):
assert prebuild_list.max() == result


@pytest.mark.parametrize(
["prebuild_list", "exception", "message"],
[
["list_str_filled", TypeError, "list of str has no maximum"],
["list_empty", TypeError, "empty list has no maximum"],
],
indirect=["prebuild_list"],
)
def test_max_err(prebuild_list, exception, message):
with pytest.raises(exception, match=message):
prebuild_list.max()


@pytest.mark.parametrize(
["prebuild_list", "result"],
[
Expand Down

0 comments on commit 4657176

Please sign in to comment.