Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

implementation of theminmax function#144382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
Marius-Juston wants to merge4 commits intopython:mainfromMarius-Juston:minmax
Closed
Show file tree
Hide file tree
Changes fromall 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 deletionsDoc/howto/sorting.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -400,6 +400,11 @@ library provides several tools that do less work than a full sort:
respectively. These functions make a single pass over the input data and
require almost no auxiliary memory.

* :func:`minmax` returns both the smallest and largest values,
respectively. This functions make a single pass over the input data and
require almost no auxiliary memory. This function is useful if both :meth:`min` and
:meth:`max` need to be called and thus is more efficient for larger datasets.

* :func:`heapq.nsmallest` and :func:`heapq.nlargest` return
the *n* smallest and largest values, respectively. These functions
make a single pass over the data keeping only *n* elements in memory
Expand Down
22 changes: 22 additions & 0 deletionsDoc/library/functions.rst
View file
Open in desktop
Original file line numberDiff line numberDiff 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 deletionsLib/test/test_builtin.py
View file
Open in desktop
Original file line numberDiff line numberDiff 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
View file
Open in desktop
Original file line numberDiff line numberDiff 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 deletionsPython/bltinmodule.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2114,6 +2114,176 @@ the provided iterable is empty.\n\
With two or more positional arguments, return the largest argument.");


static PyObject *
builtin_minmax(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *it = NULL, *item, *val, *maxitem, *maxval, *minitem, *minval, *minmax_obj, *keyfunc=NULL;
PyObject *defaultval = NULL;
static const char * const keywords[] = {"key", "default", NULL};
static _PyArg_Parser _parser = {"|$OO:minmax", keywords, 0};

if (nargs == 0) {
PyErr_Format(PyExc_TypeError, "minmax expected at least 1 argument, got 0");
return NULL;
}

if (kwnames != NULL && !_PyArg_ParseStackAndKeywords(args + nargs, 0, kwnames, &_parser,
&keyfunc, &defaultval)) {
return NULL;
}

const int positional = nargs > 1; // False iff nargs == 1
if (positional && defaultval != NULL) {
PyErr_Format(PyExc_TypeError,
"Cannot specify a default for minmax() with multiple "
"positional arguments");
return NULL;
}

if (!positional) {
it = PyObject_GetIter(args[0]);
if (it == NULL) {
return NULL;
}
}

if (keyfunc == Py_None) {
keyfunc = NULL;
}

maxitem = NULL; /* the max result */
maxval = NULL; /* the value associated with the max result */

minitem = NULL; /* the min result */
minval = NULL; /* the value associated with the min result */

while (1) {
if (it == NULL) {
if (nargs-- <= 0) {
break;
}
item = *args++;
Py_INCREF(item);
}
else {
item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred()) {
goto Fail_it;
}
break;
}
}

/* get the value from the key function */
if (keyfunc != NULL) {
val = PyObject_CallOneArg(keyfunc, item);
if (val == NULL)
goto Fail_it_item;
}
/* no key function; the value is the item */
else {
val = Py_NewRef(item);
}

/* minimum/maximum value and item are unset; set them */
if (maxval == NULL || minval == NULL) {
maxitem = item;
maxval = val;

minitem = Py_NewRef(item);
minval = Py_NewRef(val);
}
/* minimum/maximum value and item are set; update them as necessary */
else {
/* check for new minimum value */
const int cmp_lt = PyObject_RichCompareBool(val, minval, Py_LT);

if (cmp_lt < 0) {
goto Fail_it_item_and_val;
}

if (cmp_lt > 0) {
Py_DECREF(minitem);
Py_DECREF(minval);

minval = val;
minitem = item;
} else {
/* Since we did not get a new minimum it could be a new maximum instead */
const int cmp_gt = PyObject_RichCompareBool(val, maxval, Py_GT);

if (cmp_gt < 0) {
goto Fail_it_item_and_val;
}

if(cmp_gt > 0) {
Py_DECREF(maxitem);
Py_DECREF(maxval);

maxval = val;
maxitem = item;
}
else {
Py_DECREF(item);
Py_DECREF(val);
}
}
}
}
if (maxval == NULL || minval == NULL) {
assert(maxitem == NULL);
assert(minitem == NULL);
if (defaultval != NULL) {
maxitem = Py_NewRef(defaultval);
minitem = Py_NewRef(defaultval);
} else {
PyErr_Format(PyExc_ValueError,
"minmax() iterable argument is empty");

goto Fail_it;
}
}else {
Py_DECREF(maxval);
Py_DECREF(minval);
}

Py_XDECREF(it);

if ((minmax_obj = PyTuple_New(2)) == NULL) {
goto Fail_it;
}

PyTuple_SET_ITEM(minmax_obj, 0, minitem);
PyTuple_SET_ITEM(minmax_obj, 1, maxitem);

return minmax_obj;

Fail_it_item_and_val:
Py_DECREF(val);
Fail_it_item:
Py_DECREF(item);
Fail_it:
Py_XDECREF(maxval);
Py_XDECREF(maxitem);

Py_XDECREF(minval);
Py_XDECREF(minitem);

Py_XDECREF(it);
return NULL;
}

PyDoc_STRVAR(minmax_doc,
"minmax(iterable, *[, default=obj, key=func]) -> (min_value, max_value)\n\
minmax(arg1, arg2, *args, *[, key=func]) -> (min_value, max_value)\n\
\n\
With a single iterable argument, return both its smallest and biggest item. The\n\
default keyword-only argument specifies an object to return if\n\
the provided iterable is empty.\n\
With two or more positional arguments, return the smallest and largest argument.");


/*[clinic input]
oct as builtin_oct

Expand DownExpand Up@@ -3392,6 +3562,7 @@ static PyMethodDef builtin_methods[] = {
BUILTIN_LOCALS_METHODDEF
{"max", _PyCFunction_CAST(builtin_max), METH_FASTCALL | METH_KEYWORDS, max_doc},
{"min", _PyCFunction_CAST(builtin_min), METH_FASTCALL | METH_KEYWORDS, min_doc},
{"minmax", _PyCFunction_CAST(builtin_minmax), METH_FASTCALL | METH_KEYWORDS, minmax_doc},
{"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc},
BUILTIN_ANEXT_METHODDEF
BUILTIN_OCT_METHODDEF
Expand Down
Loading

[8]ページ先頭

©2009-2026 Movatter.jp