A safe max() function for empty lists
Solution 1
In Python 3.4+, you can use default
keyword argument:
>>> max([], default=99)
99
In lower version, you can use or
:
>>> max([] or [99])
99
NOTE: The second approach does not work for all iterables. especially for iterator that yield nothing but considered truth value.
>>> max(iter([]) or 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: max() arg is an empty sequence
Solution 2
In versions of Python older than 3.4 you can use itertools.chain()
to add another value to the possibly empty sequence. This will handle any empty iterable but note that it is not precisely the same as supplying the default
argument as the extra value is always included:
>>> from itertools import chain
>>> max(chain([42], []))
42
But in Python 3.4, the default is ignored if the sequence isn't empty:
>>> max([3], default=42)
3
Solution 3
Another solution could be by using ternary operators:
nums = []
max_val = max(nums) if nums else 0
or
max val = max(iter(nums) if nums else [0])
Solution 4
Can create simple lambda to do this:
get_max = lambda val_list: max([ val for val in val_list if val is not None ]) if val_list else None
You can call it this way:
get_max(your_list)
Solution 5
_DEFAULT = object()
def max_default(*args, **kwargs):
"""
Adds support for "default" keyword argument when iterable is empty.
Works for any iterable, any default value, and any Python version (versions >= 3.4
support "default" parameter natively).
Default keyword used only when iterable is empty:
>>> max_default([], default=42)
42
>>> max_default([3], default=42)
3
All original functionality is preserved:
>>> max_default([])
Traceback (most recent call last):
ValueError: max() arg is an empty sequence
>>> max_default(3, 42)
42
"""
default = kwargs.pop('default', _DEFAULT)
try:
return max(*args, **kwargs)
except ValueError:
if default is _DEFAULT:
raise
return default
Bonus:
def min_default(*args, **kwargs):
"""
Adds support for "default" keyword argument when iterable is empty.
Works for any iterable, any default value, and any Python version (versions >= 3.4
support "default" parameter natively).
Default keyword used only when iterable is empty:
>>> min_default([], default=42)
42
>>> min_default([3], default=42)
3
All original functionality is preserved:
>>> min_default([])
Traceback (most recent call last):
ValueError: min() arg is an empty sequence
>>> min_default(3, 42)
3
"""
default = kwargs.pop('default', _DEFAULT)
try:
return min(*args, **kwargs)
except ValueError:
if default is _DEFAULT:
raise
return default
Related videos on Youtube
Alexander McFarlane
I'm pretty average at snowboarding Quantitative researcher designing prop trading strategies in python Random Quotes If a man does not have to work: If he does not grow crops or hunt or do something, he very quickly destroys himself - Yaka Garimala, quoting an Aboriginal saying Physics Nobel Laureate Quotes Physics is like sex: sure, it may give some practical results, but that's not why we do it - Richard Feynman All science is either physics or stamp collecting - Ernest Rutherford Anyone who has never made a mistake has never tried anything new - Albert Einstein Because of its extreme complexity, most physicists will be glad to see the end of QED - Paul Dirac
Updated on November 20, 2020Comments
-
Alexander McFarlane over 3 years
Evaluating,
max_val = max(a)
will cause the error,
ValueError: max() arg is an empty sequence
Is there a better way of safeguarding against this error other than a
try
,except
catch?a = [] try: max_val = max(a) except ValueError: max_val = default
-
vaultah about 8 years
-
Martin Tournoij about 8 years@vaultah Why you no post answer as answer?!
-
vaultah about 8 years@Carpetsmoker: because it's too simple.
-
Martin Tournoij about 8 years@vaultah ... What's wrong with posting answers that are "too simple"? Now someone else has to...
-
-
Steven Rumbalski about 8 yearsAnother option for pre-3.4 would be to create a
my_max
function that mimics the newer behavior. -
Alexander McFarlane about 8 years
max(iter([]) or 0)
is precisely what gave me the grief in the first place... Do you have any further suggestions on what do do with it? Secondly it never occurred to me to check the docs... I assumed such a simple function was a one-in-one-out process -
falsetru about 8 years@AlexanderMcFarlane, Duncan suggested a nice alternative. Check it out.
-
falsetru about 8 years@AlexanderMcFarlane, I'm not a native speaker. I don't understand what
one-in-one-out process
. Does it mean a common task? -
Alexander McFarlane about 8 years@falsetru by one-in-one-out I mean one argument in and one return value :)
-
Yaakov Belch over 7 yearsIt's counter-intuitive: the max of an empty list should be infinitely small (so that max(x,list...)=max(x,max(list...))) and the min of an empty list should be infinitely large.
-
Gareth McCaughan over 7 yearsWhoops, yes, I wrote that the wrong way around; my apologies. I will fix my answer and credit you for spotting the mistake. [... Done. Thanks again.]
-
MajorInc over 5 yearsis there any reason to use
chain
over simple list concatenation e.g.max( [42], [] )
where the default is42
? -
Duncan over 5 years@MajorInc calling
max
with multiple arguments has a different meaning than calling it with a single argument. With a single iterable argumentmax
will return the largest element it contains, but with multiple arguments it compares them directly (i.e. it won't iterate). e.g.max([42], [])
is a list[42]
butmax(chain([42], []))
andmax([], default=42)
both give42
. -
Milo over 4 years
max_safe(42, 3, default=0)
ThrowsTypeError: max() got an unexpected keyword argument
(python 2)