Skip to content

Commit 75eec31

Browse files
committed
Added new functions for returning the "natural" min and max values from an iterable.
1 parent 4b05888 commit 75eec31

File tree

4 files changed

+91
-5
lines changed

4 files changed

+91
-5
lines changed

domdf_python_tools/iterative.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,18 @@
2525
# MA 02110-1301, USA.
2626
#
2727
# chunks from https://stackoverflow.com/a/312464/3092681
28-
# Copyright © 2008 Ned Batchelder
29-
# Licensed under CC-BY-SA
28+
# Copyright © 2008 Ned Batchelder
29+
# Licensed under CC-BY-SA
3030
#
3131

3232
# stdlib
3333
import itertools
3434
import textwrap
35-
from typing import Any, Generator, Iterable, Iterator, List, Sequence, Tuple, Type, Union
35+
from collections import Callable
36+
from typing import Any, Generator, Iterable, Iterator, List, Optional, Sequence, Tuple, Type, Union
37+
38+
# 3rd party
39+
from natsort import natsorted, ns
3640

3741
__all__ = [
3842
"chunks",
@@ -42,6 +46,8 @@
4246
"double_chain",
4347
"flatten",
4448
"make_tree",
49+
"natmin",
50+
"natmax",
4551
]
4652

4753

@@ -211,3 +217,37 @@ def make_tree(tree: Branch) -> Iterator[str]:
211217
elif isinstance(tree[-1], Iterable):
212218
for line in make_tree(tree[-1]):
213219
yield textwrap.indent(line, " ")
220+
221+
222+
def natmin(seq: Iterable, key: Optional[Callable] = None, alg: int = ns.DEFAULT):
223+
"""
224+
Returns the minimum value from ``seq`` when sorted naturally.
225+
226+
:param seq:
227+
:param key: A key used to determine how to sort each element of the iterable.
228+
It is **not** applied recursively.
229+
The callable should accept a single argument and return a single value.
230+
:param alg: This option is used to control which algorithm :mod:`natsort` uses when sorting.
231+
For details into these options, please see the :class:`ns` class documentation.
232+
233+
.. versionadded:: 1.8.0
234+
"""
235+
236+
return natsorted(seq, key=key, alg=alg)[0]
237+
238+
239+
def natmax(seq: Iterable, key: Optional[Callable] = None, alg: int = ns.DEFAULT):
240+
"""
241+
Returns the maximum value from ``seq`` when sorted naturally.
242+
243+
:param seq:
244+
:param key: A key used to determine how to sort each element of the iterable.
245+
It is **not** applied recursively.
246+
The callable should accept a single argument and return a single value.
247+
:param alg: This option is used to control which algorithm :mod:`natsort` uses when sorting.
248+
For details into these options, please see the :class:`ns` class documentation.
249+
250+
.. versionadded:: 1.8.0
251+
"""
252+
253+
return natsorted(seq, key=key, alg=alg)[-1]

domdf_python_tools/paths.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ def traverse_to_file(base_directory: _P, *filename: PathLike, height: int = -1)
782782
:param \*filename: The filename(s) to search for
783783
:param height: The maximum height to traverse to.
784784
785-
.. versionadded:: 1.6.0
785+
.. versionadded:: 1.7.0
786786
"""
787787

788788
if not filename:

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ colorama>=0.4.3
22
deprecation>=2.1.0
33
importlib-metadata>=1.5.0; python_version < "3.8"
44
importlib-resources>=3.0.0; python_version < "3.7"
5+
natsort>=7.1.0
56
packaging>=20.4
67
pydash>=4.7.4
78
typing-extensions>=3.7.4.3

tests/test_iterative.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
# stdlib
10+
from random import shuffle
1011
from types import GeneratorType
1112

1213
# 3rd party
@@ -15,7 +16,17 @@
1516
from pytest_regressions.file_regression import FileRegressionFixture
1617

1718
# this package
18-
from domdf_python_tools.iterative import Len, chunks, double_chain, flatten, make_tree, permutations, split_len
19+
from domdf_python_tools.iterative import (
20+
Len,
21+
chunks,
22+
double_chain,
23+
flatten,
24+
make_tree,
25+
natmax,
26+
natmin,
27+
permutations,
28+
split_len
29+
)
1930
from domdf_python_tools.testing import check_file_regression
2031

2132

@@ -147,3 +158,37 @@ def test_make_tree(file_regression: FileRegressionFixture):
147158
)
148159
def test_flatten(data, data_regression: DataRegressionFixture):
149160
data_regression.check(list(flatten(data)))
161+
162+
163+
@pytest.mark.parametrize(
164+
"data",
165+
[
166+
pytest.param([1, 3, 5, 7, 9], id="integers"),
167+
pytest.param([1.2, 3.4, 5.6, 7.8, 9.0], id="floats"),
168+
pytest.param(['1', '3', '5', '7', '9'], id="numerical_strings"),
169+
pytest.param(["1.2", "3.4", "5.6", "7.8", "9.0"], id="float strings"),
170+
pytest.param(["0.9", "0.12.4", '1', "2.5"], id="versions"),
171+
]
172+
)
173+
def test_natmin(data):
174+
orig_data = data[:]
175+
for _ in range(5):
176+
shuffle(data)
177+
assert natmin(data) == orig_data[0]
178+
179+
180+
@pytest.mark.parametrize(
181+
"data",
182+
[
183+
pytest.param([1, 3, 5, 7, 9], id="integers"),
184+
pytest.param([1.2, 3.4, 5.6, 7.8, 9.0], id="floats"),
185+
pytest.param(['1', '3', '5', '7', '9'], id="numerical_strings"),
186+
pytest.param(["1.2", "3.4", "5.6", "7.8", "9.0"], id="float strings"),
187+
pytest.param(["0.9", "0.12.4", '1', "2.5"], id="versions"),
188+
]
189+
)
190+
def test_natmax(data):
191+
orig_data = data[:]
192+
for _ in range(5):
193+
shuffle(data)
194+
assert natmax(data) == orig_data[-1]

0 commit comments

Comments
 (0)