implementation of the `minmax` function by Marius-Juston · Pull Request #144382 · python/cpython · GitHub
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions Doc/howto/sorting.rst
22 changes: 22 additions & 0 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,28 @@ are always available. They are listed here in alphabetical order.
.. versionchanged:: 3.8
The *key* can be ``None``.

.. function:: minmax(iterable, /, *, key=None)
minmax(iterable, /, *, default, key=None)
minmax(arg1, arg2, /, *args, key=None)

Return the smallest and largest items respectively in an iterable or the smallest and largest
of two or more arguments.

If one positional argument is provided, it should be an :term:`iterable`.
The smallest and largest items in the iterable are returned. If two or more positional
arguments are provided, the smallest and largest of the positional arguments are
returned.

There are two optional keyword-only arguments. The *key* argument specifies
a one-argument ordering function like that used for :meth:`list.sort`. The
*default* argument specifies an object to return if the provided iterable is
empty. If the iterable is empty and *default* is not provided, a
:exc:`ValueError` is raised.

If multiple items are minimal / maximal, the function returns the first one
encountered. This is consistent with other sort-stability preserving tools
such as ``(sorted(iterable, key=keyfunc)[0], sorted(iterable, key=keyfunc)[-1])``
and ``(heapq.nsmallest(1,iterable, key=keyfunc), heapq.nlargest(1,iterable, key=keyfunc))``.

.. function:: next(iterator, /)
next(iterator, default, /)
Expand Down
66 changes: 66 additions & 0 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1630,6 +1630,72 @@ def __getitem__(self, index):
self.assertEqual(min(data, key=f),
sorted(data, key=f)[0])


def test_minmax(self):
self.assertEqual(minmax('123123'), ('1', '3'))
self.assertEqual(minmax(1, 2, 3), (1, 3))
self.assertEqual(minmax((1, 2, 3, 1, 2, 3)), (1, 3))
self.assertEqual(minmax([1, 2, 3, 1, 2, 3]), (1, 3))

self.assertEqual(minmax(1, 2, 3.0), (1, 3.0))
self.assertEqual(minmax(1, 2.0, 3), (1, 3))
self.assertEqual(minmax(1.0, 2, 3), (1.0, 3))

with self.assertRaisesRegex(
TypeError,
'minmax expected at least 1 argument, got 0'
):
minmax()

self.assertRaises(TypeError, minmax, 42)
with self.assertRaisesRegex(
ValueError,
r'minmax\(\) iterable argument is empty'
):
minmax(())
class BadSeq:
def __getitem__(self, index):
raise ValueError
self.assertRaises(ValueError, minmax, BadSeq())

for stmt in (
"minmax(key=int)", # no args
"minmax(default=None)",
"minmax(1, 2, default=None)", # require container for default
"minmax(default=None, key=int)",
"minmax(1, key=int)", # single arg not iterable
"minmax(1, 2, keystone=int)", # wrong keyword
"minmax(1, 2, key=int, abc=int)", # two many keywords
"minmax(1, 2, key=1)", # keyfunc is not callable
):
try:
exec(stmt, globals())
except TypeError:
pass
else:
self.fail(stmt)

self.assertEqual(minmax((1,), key=neg), (1, 1)) # one elem iterable
self.assertEqual(minmax((1,2), key=neg),(2, 1)) # two elem iterable
self.assertEqual(minmax(1, 2, key=neg), (2, 1)) # two elems

self.assertEqual(minmax((), default=None), (None, None)) # zero elem iterable
self.assertEqual(minmax((1,), default=None), (1, 1)) # one elem iterable
self.assertEqual(minmax((1,2), default=None), (1, 2)) # two elem iterable

self.assertEqual(minmax((), default=1, key=neg), (1, 1))
self.assertEqual(minmax((1, 2), default=1, key=neg), (2, 1))

self.assertEqual(minmax((1, 2), key=None), (1, 2))

data = [random.randrange(200) for i in range(100)]
keys = dict((elem, random.randrange(50)) for elem in data)
f = keys.__getitem__

sorted_vals = sorted(data, key=f)
self.assertEqual(minmax(data, key=f),
(sorted_vals[0], sorted_vals[-1]))

def test_next(self):
it = iter(range(2))
self.assertEqual(next(it), 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This creates a new builtin function called ``minmax``, which does work similar
to the functions ``min`` and ``max``; however, is more efficient than running
``min`` and then ``max`` and computes the smallest and largest elements of the
iterable in a single pass; rather than 2 passes.
171 changes: 171 additions & 0 deletions Python/bltinmodule.c
Loading