Minmax function alongside min and max

@ruud Anyway, if you want to support also default, I think that, before you return it, you should transform it to a tuple and check if its length is 2. Otherwise, an error should be raised.

Obviously not as evident as you presume, from the reactions to ypur example.

Given the “two different placements of NaN” example, I would think its the fault of trying to find the minimum of results containing NaN’s. I would be at fault for not accounting for NaN’s. Ignoring them, or any other action could depend on circumstance - wh’s to say that an arbitrary resolution is th one needed?

It might be better still to raise an exception unless an option is given to state how NaN’s should be treated - at least they won’t silently be ignored.

1 Like

@Paddy3118 Please discuss this here:
https://discuss.python.org/t/2868

Marco, point us at official Python documentation that documents what min
and max are supposed to do when passed values that don’t provide a total
order, and if that documented behaviour is different from what the
functions actually do, then we will conceed that it is a bug.

There are at least three different things that min(0, NAN) could do:

  • propogate the NAN (return a NAN)
  • ignore the NAN (return 0)
  • raise an exception

and no consensus on what it should do. At least half our users will
consider your version to be “buggy” since it doesn’t match their
expectations. You don’t get to unilaterally decide what is correct and
what is buggy.

If you want to change this, you will need to write a PEP. You should
consider the two different versions of min/max that the IEEE-754
standard specifies, plus any other versions that others may desire
(such as a version which raises an exception).

It isn’t enough to specify the behaviour with NANs, there are an
infinite number of ways a data set can fail to provide a total order.
For instance, dominance heirarchies are often not a total order, for
example Rock Paper Scissors:

Rock > Scissors
Scissors > Paper
Paper > Rock

max(Rock, Paper, Scissors) should do what?

Unless you are prepared to write a PEP, there’s no point in you
continuing this argument. There is no agreement on what the “correct”
behaviour is, so any version we provide will surprise some people. The
best we can do is explicitly document that the behaviour for data sets
that don’t define a total order will be implementation-defined and
therefore we make no promise about what will happen.

(The fact that min and max currently ignore NANs that aren’t in the
first position is an accident, not an intentional behaviour.)

Paul: “undefined behaviour” has special meaning to C programmers which
it doesn’t have to other language programmers. Given the special place C
has in the programming ecosystem, I prefer to honour their definition,
and use “implementation-defined behaviour” for what we are talking about
here.

2 Likes

@steven.daprano *sigh* please discuss it here… and please read first the posts:
https://discuss.python.org/t/2868

1 Like

Thanks, that’s a good point. I do like the connotations of C’s “undefined behaviour” (in general, but in this discussion in particular) but if it’s not a familiar idea to people in general, it’s probably just confusing the discussion. I’ll keep this in mind.

1 Like

As a reminder to people, posts can be flagged to the admins to handle potential PSF Code of Conduct issues so they can be dealt with appropriately.

Please Mark, “even a baby can do it” and similar phrases is a standard
English idiom for “its easy”. Its no more disrespectful than if Marco
had said “It is easy to understand that code”.

It is not an aggression, not even a microagression or a nanoaggression,
although I suppose the mere fact that Marco is disagreeing with me makes
it a picoaggression. I think I can cope with mere disagreement wink

Can we please assume good faith and not be so touchy that everyone has
to walk around on eggshells for fear of being banned for the most
innocuous comment?

2 Likes

It should not only restrict to find min max numbers, other functionalities also include e.g comparisons of min max of two lists, string lengths etc. It will helpful in spatial data as well.

I don’t want this thread to devolve into a CoC discussion (or really get into one period), but the issues went beyond just the “baby” comment. And in regards to that specific comment, it could still be insulting to someone who actually didn’t find it easy to understand and so feels like a put-down. Simply saying “I think it’s easy to understand” would have been enough to get the point across and not risk insulting someone accidentally.

4 Likes

There’s something of a parallel with the built-in function divmod here. There’s an excellent reason for having divmod available, namely that it’s common to want to compute both a // b and a % b as part of some algorithm, and computing them separately is needlessly inefficient: in current CPython, a // b (for a and b of type int) computes both the quotient and the remainder, then throws the remainder away and returns the quotient. Similarly for a % b. So by evaluating a // b and a % b separately you’re computing the quotient and the remainder twice each instead of once. divmod solves this inefficiency.

Nevertheless, I’ve always found divmod oddly unsatisfying in practice, and despite writing a lot of integer-based algorithmic code, I almost never use divmod, and I rarely see it used in other people’s code. Part of the issue is readability: if I have an expression that uses both a % b and a // b and I want to use divmod for efficiency, I have to introduce a separate statement to call divmod(a, b) and unpack the resulting tuple. I can’t simply use divmod directly in my expression without using it twice, which defeats the point. So my functional-style code becomes more procedural and a mite harder to read as a result, especially since a function call is being substituted for operators.

I don’t know if we have, or can get, statistics on usage of builtins, but I’d hazard a guess that divmod is one of the least-used built-in functions. (To be clear, before anyone gets excited, I am not proposing that divmod be deprecated, moved, or removed. It is what it is.)

I suspect minmax would suffer from some of the same issues, though we don’t have the operator versus function call aspect. I think it wouldn’t get used as much as one might a priori expect. It might be useful to look at some before-and-after examples from real-world code to see to what extent readability is affected.

That’s not to say that minmax wouldn’t be useful, but in spite of min and max being builtins, I doubt that minmax would be useful often enough to justify adding it to builtins. Which leaves us with the issue of figuring out where it does belong, and I don’t have a good answer to that. math, statistics and itertools seem like the obvious candidates. Of the three, I’d probably go with math: it bothers me a bit that minmax, like min and max, wouldn’t necessarily be specifically for numbers, which makes math seem inappropriate, but we already have a precedent for putting a generic not-necessarily-numeric function in math, in the form of math.prod.

4 Likes

Out of idle curiosity how many of these statistical functions would there be that would benefit from a “continuous” evaluation of their value? (Ignoring the discussion on NAN for a moment)

Would there be value in a function that would evaluate a range of statistical values in a single live pass?

Min/Max
Sum
A//B
A%B

Possibly returning a tuple in the order that the functions were requested?