Меню

Max arg is an empty sequence python ошибка

Since you are always initialising self.listMyData to an empty list in clkFindMost your code will always lead to this error* because after that both unique_names and frequencies are empty iterables, so fix this.

Another thing is that since you’re iterating over a set in that method then calculating frequency makes no sense as set contain only unique items, so frequency of each item is always going to be 1.

Lastly dict.get is a method not a list or dictionary so you can’t use [] with it:

Correct way is:

if frequencies.get(name):

And Pythonic way is:

if name in frequencies:

The Pythonic way to get the frequency of items is to use collections.Counter:

from collections import Counter   #Add this at the top of file.

def clkFindMost(self, parent):

        #self.listMyData = []   
        if self.listMyData:
           frequencies = Counter(self.listMyData)
           self.txtResults.Value = max(frequencies, key=frequencies.get)
        else:
           self.txtResults.Value = '' 

max() and min() throw such error when an empty iterable is passed to them. You can check the length of v before calling max() on it.

>>> lst = []
>>> max(lst)

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    max(lst)
ValueError: max() arg is an empty sequence
>>> if lst:
    mx = max(lst)
else:
    #Handle this here

If you are using it with an iterator then you need to consume the iterator first before calling max() on it because boolean value of iterator is always True, so we can’t use if on them directly:

>>> it = iter([])
>>> bool(it)
True
>>> lst = list(it)
>>> if lst:
       mx = max(lst)
    else:
      #Handle this here   

Good news is starting from Python 3.4 you will be able to specify an optional return value for min() and max() in case of empty iterable.

The max() function is built into Python and returns the item with the highest value in an iterable or the item with the highest value from two or more objects of the same type. When you pass an iterable to the max() function, such as a list, it must have at least one value to work. If you use the max() function on an empty list, you will raise the error “ValueError: max() arg is an empty sequence”.

To solve this error, ensure you only pass iterables to the max() function with at least one value. You can check if an iterable has more than one item by using an if-statement, for example,

if len(iterable) > 0: 
    max_value = max(iterable)

This tutorial will go through the error in detail and how to solve it with a code example.


Table of contents

  • ValueError: max() arg is an empty sequence
    • What is a Value Error in Python?
    • Using max() in Python
  • Example: Returning a Maximum Value from a List using max() in Python
    • Solution
  • Summary

ValueError: max() arg is an empty sequence

What is a Value Error in Python?

In Python, a value is a piece of information stored within a particular object. You will encounter a ValueError in Python when you use a built-in operation or function that receives an argument with the right type but an inappropriate value. Let’s look at an example of a ValueError:

value = 'string'

print(float(value))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
print(float(value))

ValueError: could not convert string to float: 'string'

The above code throws the ValueError because the value ‘string‘ is an inappropriate (non-convertible) string. You can only convert numerical strings using the float() method, for example:

value = '5'
print(float(value))
5.0

The code does not throw an error because the float function can convert a numerical string. The value of 5 is appropriate for the float function.

The error ValueError: max() arg is an empty sequence is a ValueError because while an iterable is a valid type of object to pass to the max() function, the value it contains is not valid.

Using max() in Python

The max() function returns the largest item in an iterable or the largest of two or more arguments. Let’s look at an example of the max() function to find the maximum of three integers:

var_1 = 3
var_2 = 5
var_3 = 2

max_val = max(var_1, var_2, var_2)

print(max_val)

The arguments of the max() function are the three integer variable. Let’s run the code to get the result:

5

Let’s look at an example of passing an iterable to the max() function. In this case, we will use a string. The max() function finds the maximum alphabetical character in a string.

string = "research"

max_val = max(string)

print(max_val)

Let’s run the code to get the result:

s

When you pass an iterable the max() function, it must contain at least one value. The max() function cannot return the largest item if no items are present in the list. The same applies to the min() function, which finds the smallest item in a list.

Example: Returning a Maximum Value from a List using max() in Python

Let’s write a program that finds the maximum number of bottles sold for different drinks across a week. First, we will define a list of drinks:

drinks = [

{"name":"Coca-Cola", "bottles_sold":[10, 4, 20, 50, 29, 100, 70]},

{"name":"Fanta", "bottles_sold":[20, 5, 10, 50, 90, 10, 50]},

{"name":"Sprite", "bottles_sold":[33, 10, 8, 7, 34, 50, 21]},

{"name":"Dr Pepper", "bottles_sold":[]}

]

The list contains four dictionaries. Each dictionary contains the name of a drink and a list of the bottles sold over seven days. The drink Dr Pepper recently arrived, meaning no bottles were sold. Next, we will iterate over the list using a for loop and find the largest amount of bottles sold for each drink over seven days.

for d in drinks:

    most_bottles_sold = max(d["bottles_sold"])

    print("The largest amount of {} bottles sold this week is {}.".format(d["name"], most_bottles_sold))

We use the max() function in the above code to get the largest item in the bottles_sold list. Let’s run the code to get the result:

The largest amount of Coca-Cola bottles sold this week is 100.
The largest amount of Fanta bottles sold this week is 90.
The largest amount of Sprite bottles sold this week is 50.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
      1 for d in drinks:
      2     most_bottles_sold = max(d["bottles_sold"])
      3     print("The largest amount of {} bottles sold this week is {}.".format(d["name"], most_bottles_sold))
      4 

ValueError: max() arg is an empty sequence

The program raises the ValueError because Dr Pepper has an empty list.

Solution

To solve this error, we can add an if statement to check if any bottles were sold in a week before using the max() function. Let’s look at the revised code:

for d in drinks:

    if len(d["bottles_sold"]) > 0:

        most_bottles_sold = max(d["bottles_sold"])

        print("The largest amount of {} bottles sold this week is {}.".format(d["name"], most_bottles_sold)

    else:

        print("No {} bottles were sold this week.".format(d["name"]))

The program will only calculate the maximum amount of bottles sold for a drink if it was sold for at least one day. Otherwise, the program will inform us that the drink was not sold for that week. Let’s run the code to get the result:

The largest amount of Coca-Cola bottles sold this week is 100.
The largest amount of Fanta bottles sold this week is 90.
The largest amount of Sprite bottles sold this week is 50.
No Dr Pepper bottles were sold this week.

The program successfully prints the maximum amount of bottles sold for Coca-Cola, Fanta, and Sprite. The bottles_sold list for Dr Pepper is empty; therefore, the program informs us that no Dr Pepper bottles were sold this week.

Summary

Congratulations on reading to the end of this tutorial! The error: “ValueError: max() arg is an empty sequence” occurs when you pass an empty list as an argument to the max() function. The max() function cannot find the largest item in an iterable if there are no items. To solve this, ensure your list has items or include an if statement in your program to check if a list is empty before calling the max() function.

For further reading of ValueError, go to the articles:

  • How to Solve Python ValueError: cannot convert float nan to integer
  • How to Solve Python ValueError: if using all scalar values, you must pass an index

For further reading on using the max() function, go to the article:

How to Find the Index of the Max Value in a List in Python

Go to the Python online courses page to learn more about coding in Python for data science and machine learning.

Have fun and happy researching!

The max() method only works if you pass a sequence with at least one value into the method.

If you try to find the largest item in an empty list, you’ll encounter the error “ValueError: max() arg is an empty sequence”.

Get offers and scholarships from top coding schools illustration

Find Your Bootcamp Match

  • Career Karma matches you with top tech bootcamps
  • Access exclusive scholarships and prep courses

Select your interest

First name

Last name

Email

Phone number

By continuing you agree to our Terms of Service and Privacy Policy, and you consent to receive offers and opportunities from Career Karma by telephone, text message, and email.

In this guide, we talk about what this error means and why you may encounter it. We walk through an example to help you figure out how to resolve this error.

ValueError: max() arg is an empty sequence

The max() method lets you find the largest item in a list. It is similar to the min() method which finds the smallest item in a list.

For this method to work, max() needs a sequence with at least one value. This is because you cannot find the largest item in a list if there are no items. The largest item is non-existent because there are no items to search through.

A variation of the “ValueError: max() arg is an empty sequence” error is found when you try to pass an empty list into the min() method. This error is “ValueError: min() arg is an empty sequence”. This min() error occurs for the same reason: you cannot find the smallest value in a list with no values.

An Example Scenario

We’re going to build a program that finds the highest grade a student has earned in all their chemistry tests. To start, define a list of students:

students = [
	   { "name": "Ron", "grades": [75, 92, 84] },
	   { "name": "Katy", "grades": [92, 86, 81] },
	   { "name": "Rachel", "grades": [64, 72, 72] },
	   { "name": "Miranda", "grades": [] }
]

Our list of students contains four dictionaries. These dictionaries contain the names of each student as well as a list of the grades they have earned. Miranda does not have any grades yet because she has just joined the chemistry class.

Next, use a for loop to go through each student in our list of students and find the highest grade each student has earned and the average grade of each student:

for s in students:
	     highest_grade = max(s["grades"])
	     average_grade = round(sum(s["grades"]) / len(s["grades"]))
	     print("The highest grade {} has earned is {}. Their average grade is {}.".format(s["name"], highest_grade, average_grade))

We use the max() function to find the highest grade a student has earned. To calculate a student’s average grade, we divide the total of all their grades by the number of grades they have received.

We round each student’s average grade to the nearest whole number using the round() method.

Run our code and see what happens:

The highest grade Ron has earned is 92. Their average grade is 84.
The highest grade Katy has earned is 92. Their average grade is 86.
The highest grade Rachel has earned is 72. Their average grade is 69.
Traceback (most recent call last):
  File "main.py", line 10, in <module>
	     highest_grade = max(s["grades"])
ValueError: max() arg is an empty sequence

Our code runs successfully until it reaches the fourth item in our list. We can see Ron, Katy, and Rachel’s highest and average grades. We cannot see any values for Miranda.

The Solution

Our code works on the first three students because each of those students have a list of grades with at least one grade. Miranda does not have any grades yet. 

Because Miranda does not have any grades, the max() function fails to execute. max() cannot find the largest value in an empty list.

To solve this error, see if each list of grades contains any values before we try to calculate the highest grade in a list. If a list contains no values, we should show a different message to the user.

Let’s use an “if” statement to check if a student has any grades before we perform any calculations:

for s in students:
	     if len(s["grades"]) > 0:
	               highest_grade = max(s["grades"])
	               average_grade = round(sum(s["grades"]) / len(s["grades"]))
	               print("The highest grade {} has earned is {}. Their                average grade is {}.".format(s["name"], highest_grade, average_grade))
	     else:
		           print("{} has not earned any grades.".format(s["name"]))

Our code above will only calculate a student’s highest and average grade if they have earned at least one grade. Otherwise, the user will be informed that the student has not earned any grades. Let’s run our code:

The highest grade Ron has earned is 92. Their average grade is 84.
The highest grade Katy has earned is 92. Their average grade is 86.
The highest grade Rachel has earned is 72. Their average grade is 69.
Miranda has not earned any grades.

Our code successfully calculates the highest and average grades for our first three students. When our code reaches Miranda, our code does not calculate her highest and average grades. Instead, our code informs us that Miranda has not earned any grades yet.

Conclusion

The “ValueError: max() arg is an empty sequence” error is raised when you try to find the largest item in an empty list using the max() method.

To solve this error, make sure you only pass lists with at least one value through a max() statement. Now you have the knowledge you need to fix this problem like a professional coder!

In Python, an inbuilt function “max()” is used in a program to find the maximum value of the input sequence. Trying to execute the “max()” function on an empty sequence will throw the “max() arg is an empty sequence” error in Python. To resolve this error, various solutions are provided by Python.

This Python write-up will give you the reason and various solutions for “ValueError: max() arg is an empty sequence”.

  • Reason: Passing Empty Sequence
  • Solution 1: Passing Sequence With Values
  • Solution 2: Using the “default” Parameter
  • Solution 3: Using len() Function
  • Solution 4: Using try-except

Reason: Passing Empty Sequence

One of the prominent reasons which cause this error in Python programs is initializing an empty sequence as an argument to the “max()” function.

The above snippet shows “ValueError” because an empty dictionary sequence “dict_value” is passed inside the max() function.

Solution 1: Passing Sequence With Values

To resolve this error, a sequence containing at least one value must be passed to the max() function.

Code:

dict_value = {5:'Lily', 10: 'John'}
Output = max(dict_value)
print(Output)

In the above code, a sequence “dict_value” with multiple elements is initialized in the program. The “max()” function accepts the “dict_value” variable as an argument and returns the dictionary key having the maximum value.

Output:

The above output shows that the max() function retrieves the maximum dictionary key from the input dictionary sequence.

Solution 2: Using the “default” Parameter

This error can also be overcome in Python by assigning the “default” parameter value to “0”.

Code:

dict_value = {}
Output = max(dict_value, default=0)
print(Output)

In the above code, the dictionary variable “dict_value” is initialized with an empty value. The “max()” function accepts two arguments, the input variable “dict_Value” and the default parameter “default=0”. Whenever the input sequence is empty, the “max()” function returns the value “0” by default.

Output:

The above output verified that the input sequence is empty.

Solution 3: Using len() Function

To overcome this error, the “len()” function is also used in Python programs. The “len()” function is used along with the “if-else” statement to get the length and perform the operation on the input sequence based on the specified condition.

Code;

dict_value = {}
if len(dict_value)>0:
    Output = max(dict_value)
    print(Output)
else:
    print('Input Sequence is Empty')

In the above code, the “dict_value” dictionary sequence variable is initialized in the program. The “max()” function will be used on the input sequences if the length of the sequence is greater than “0”; otherwise, the “else” block will execute.

Output:

The above output shows that the input sequence is empty.

Solution 4: Using try-except

The “try-except” is also used to handle the “ValueError: max() arg is an empty sequence” in Python. Let’s see it via the following code:

Code:

dict_value = {}

try: 
    Output = max(dict_value)
    print(Output)
except:
    print('Input Sequence is Empty')

In the above code, the variable “dict_value” is initialized in the program. The “try” block executes its code and finds the maximum value of the input sequence using the “max()” function. But if the error arises, the “except” block will execute its code.

Output:

The above output shows that the “except” block executes its code because the input sequence is empty.

Conclusion

The “ValueError: max() arg is an empty sequence” occurs when a user tries to pass an empty sequence as an argument to the max() function. To resolve this error, various solutions are used in Python, such as passing sequence value, using default parameters, using the len() function, and using the try-except block. The “len()” function can be utilized along with the “if-else” statement to resolve this error. This article delivered multiple solutions for the error “max() arg is an empty sequence” in Python.

Python

max()

is an inbuilt function that can accept an iterable object and return the largest value from it. Instead of an iterable object, we can also pass more than one argument value to the

max()

function, and it will return the largest value. But if we pass an empty iterable object like an empty list, empty string, empty tuple, or empty set in the max function, it will throw the Error

ValueError: max() arg is an empty sequence

.

In this Python tutorial, we will discuss this error statement in detail and learn how to solve it. We will also walk through an example that will demonstrate this error, and in the solution section, we will solve that error.

In Python, we often use

max()

and min() functions to get the largest and smallest value from a list, tuple, and string. And instead of writing a simple comparison operation, we can use the max() or min() methods to find out the minimum and maximum values.

The max() function will only work if we pass a non-empty iterable object as an argument, and all the values of that iterable object must be of the same data type. If we pass an empty iterable object as an argument value to the max() method, we will encounter the

ValueError: max() arg is an empty sequence

Error.

Now Let’s discuss the Error statement in detail. The Error statement can further be divided into two parts

  1. ValueError (Exception Type)
  2. max() arg is an empty sequence


1. ValueError

The ValueError is one of the Python standard exceptions. It is raised in a Python program when we specify the right argument data type to a function, but the value of that argument is wrong. We can pass iterable objects to the max() method, but if the iterable object is empty, it raises the ValueError Exception.


2. max() arg is an empty sequence


max() arg is an empty sequence

is the Error Message, it is raised along with the ValueError to tell the programmer more specific detail about the error. This error message tells us that the iterable sequential argument we passed to the max() method is an empty object.


Example

my_nums = []  #empty string

largest_num = max(my_num)


Output

Traceback (most recent call last):
   File "<stdin>", line 3, in <module>
ValueError: max() arg is an empty sequence


Common Example Scenario

Now we know why this error raises in a Python program. Let’s discuss an example of how we can solve this error. We have a

prices

list that is supposed to contain the prices of the different products. And we need to create

a program

that asks the user to enter all the prices of the product they brought from the store. And return the largest value price from the

prices

list.

Let’s say if the user buys

0

products from the store, in that case, if we apply the max() method on our

prices

list we will get the error.


Error Example

# list of all prices
prices =[]

# number of products
products = 0

for number in range(products):
    price = float(input(f"Enter the price of product {number +1}"))
    # append the price in the prices list
    prices.append(price)

# find the largest price
most_expensive = max(prices)

print("The most expensive product price is: ",most_expensive )


Output

Traceback (most recent call last):
  File "C:UserstsmehraDesktopcodemain.py", line 13, in 
    most_expensive = max(prices)
ValueError: max() arg is an empty sequence


Break the code

In this example, we are getting this error because the list

prices

passed to the

max()

function is empty. The value of products is 0. That’s why we are not able to append values to the

prices

list, which makes a list empty, and the empty list causes the error with the max function.


Solution

If you encounter such situations where the list object depends on some other statements, it might be possible that the iterable object can be empty. In such cases, we can specify a default argument value to the max function that will be returned if the iterable object is empty.

max(iterable_object, default = value)


Example Solution

# list of all prices
prices =[]

# number of products
products = 0

for number in range(products):
    price = float(input(f"Enter the price of product {number +1}: "))
    # append the price in the prices list
    prices.append(price)

# find the largest price
most_expensive = max(prices, default = 0.0)

print("The most expensive product price is: ",most_expensive )


Output

The most expensive product price is: 0.0


Wrapping Up!

The Error

ValueError: max() arg is an empty sequence

raises in a Python program when we pass an empty iterable object to the max method. To solve this error, we need to make sure that we are passing a non-empty iterable object to the max() method. If the program is all dynamic and the iterable object elements depend on the program run, there we can specify the default argument in the max() method after the iterable object, so in the case of an empty iterable object, the max() method return the default value, not the error.

If you are still getting this error in your Python program, you can share your code in the comment section. We will try to help you in debugging.


People are also reading:

  • Python SyntaxError: non-default argument follows default argument Solution

  • Install Python package using Jupyter Notebook

  • Python FileNotFoundError: [Errno 2] No such file or directory Solution

  • Online Python Compiler

  • Python RecursionError: maximum recursion depth exceeded while calling a Python object

  • How to run a python script?

  • Python TypeError: can only join an iterable Solution

  • What is Python used for?

  • Python SyntaxError: cannot assign to operator Solution

  • Encrypt and Decrypt Files in Python

ValueError: max( ) arg is an empty sequence

In this article, we will learn about the error ValueError: max( ) arg is an empty sequence.
In python, the max( ) method returns the largest or greatest value in an iterable object.
An iterable object could be anything a list, a tuple, a set, or a dictionary.

Let’s understand it more with the help of an example.

Example:

#Creating list 'MyList'
MyList= [ ]

#Using max() method
print(max(MyList))

Output:

file "intobj.py", line 5, in <module>
print(max(MyList))
ValueError: max() arg is an empty sequence

In the above example, we created an empty list i.e a list with no items. Then we passed it as an argument for max( ) method. Then, when we tried compiling the program. We encountered an error in line 5 i.e ValueError: max() arg is an empty sequence. This Is because max( ) method has an empty iterable as an argument.

ValueError: min( ) arg is an empty sequence

Solution: How the max method works when passed a non-empty list?

Example:

#Creating list ‘MyList’
MyList= [3,34,123]

#Using max() method
print(max(MyList))

Output:

123

In the above example we created a list with 3 items in it. Then we passed ‘MyList’ as an argument in max( ) method. And the max( ) method returned the largest number among the 3 available numbers or items.

When I run the code like below.
I’ve got stack at the titled error.
why??

Using TensorFlow backend.
2018-05-22 11:47:25.286883: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.2 AVX AVX2 FMA
Epoch 1/15
Traceback (most recent call last):
File «test.py», line 9, in
model.train(x_train, y_train, x_valid, y_valid)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/anago/wrapper.py», line 50, in train
trainer.train(x_train, y_train, x_valid, y_valid)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/anago/trainer.py», line 51, in train
callbacks=callbacks)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/keras/legacy/interfaces.py», line 91, in wrapper
return func(*args, **kwargs)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/keras/engine/training.py», line 2145, in fit_generator
generator_output = next(output_generator)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/keras/utils/data_utils.py», line 770, in get
six.reraise(value.class, value, value.traceback)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/six.py», line 693, in reraise
raise value
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/keras/utils/data_utils.py», line 635, in _data_generator_task
generator_output = next(self._generator)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/anago/reader.py», line 137, in data_generator
yield preprocessor.transform(X, y)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/anago/preprocess.py», line 115, in transform
sents, y = self.pad_sequence(words, chars, y)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/anago/preprocess.py», line 148, in pad_sequence
word_ids, sequence_lengths = pad_sequences(word_ids, 0)
File «/Users/norio.kosaka/anaconda3/envs/py36/lib/python3.6/site-packages/anago/preprocess.py», line 197, in pad_sequences
max_length = len(max(sequences, key=len))
ValueError: max() arg is an empty sequence

import anago
from anago.reader import load_data_and_labels

x_train, y_train = load_data_and_labels('./data/train.txt')
x_valid, y_valid = load_data_and_labels('./data/valid.txt')
x_test, y_test = load_data_and_labels('./data/test.txt')

model = anago.Sequence()
model.train(x_train, y_train, x_valid, y_valid)
model.eval(x_test, y_test)
words = 'President Obama is speaking at the White House.'.split()
model.analyze(words)

Thread Rating:

  • 0 Vote(s) — 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5

error: max() arg is an empty sequence

Oct-10-2016, 08:00 PM
(This post was last modified: Oct-10-2016, 08:19 PM by Yoriz.)

Hello everyone, 

I’m trying to compile this code:

for idx, i in enumerate(array):
    if  idx > phaseshift:
        if  abs(i - array[idx - phaseshift]) > 1000 or True:
            self.phasespace_x.append(array[idx - phaseshift])
            self.phasespace_y.append(i + array[idx - phaseshift])
            self.linx = [max(self.phasespace_x),min(self.phasespace_x)]

where the problem was at first in array variable. It was not defined. To reduce the error in the «enumerate » line I defined array as empty list as: array=[]. Because when I defined array as integer I got an error that integer in enumerate cannot be interated . 

Now I have this:

Error:

ValueError: max() arg is an empty sequence

which is quite logic I think because of empty variable array. Could you please tell me how to fix this problem? 

Thank you.

Posts: 2,141

Threads: 35

Joined: Sep 2016

Reputation:
192

You could give a default value that’s returned by max If the iterable is empty.

values = []
print(max(values, default=0))

Output:

0

Posts: 9

Threads: 3

Joined: Oct 2016

Reputation:
0

(Oct-10-2016, 08:17 PM)Yoriz Wrote: You could give a default value that’s returned by max If the iterable is empty.

values = []
print(max(values, default=0))

Output:

0

Thank you. Problem removed. 🙂

Possibly Related Threads…
Thread Author Replies Views Last Post
  TypeError: sequence item 0: expected str instance, float found Error Query eddywinch82 1 3,139 Sep-04-2021, 09:16 PM
Last Post: eddywinch82
  Error : «can’t multiply sequence by non-int of type ‘float’ « Ala 3 2,253 Apr-13-2021, 10:33 AM
Last Post: deanhystad
  Empty response to request causing .json() to error t4keheart 1 5,598 Jun-26-2020, 08:35 PM
Last Post: bowlofred
  empty json file error mcmxl22 1 6,791 Jun-17-2020, 10:20 AM
Last Post: buran
  PyODBC error — second parameter to executemany must be a sequence, iterator, or gener RBeck22 1 5,641 Mar-29-2019, 06:44 PM
Last Post: RBeck22
  ValueError — arg is an empty sequence jojotte 2 4,535 Dec-31-2018, 10:07 AM
Last Post: jojotte

Python’s built-in min() and max() functions come in handy when you need to find the smallest and largest values in an iterable or in a series of regular arguments. Even though these might seem like fairly basic computations, they turn out to have many interesting use cases in real-world programing. You’ll try out some of those use cases here.

In this tutorial, you’ll learn how to:

  • Use Python’s min() and max() to find smallest and largest values in your data
  • Call min() and max() with a single iterable or with any number of regular arguments
  • Use min() and max() with strings and dictionaries
  • Tweak the behavior of min() and max() with the key and default arguments
  • Use comprehensions and generator expressions as arguments to min() and max()

Once you have this knowledge under your belt, then you’ll be prepared to write a bunch of practical examples that will showcase the usefulness of min() and max(). Finally, you’ll code your own versions of min() and max() in pure Python, which can help you understand how these functions work internally.

To get the most out of this tutorial, you should have some previous knowledge of Python programming, including topics like for loops, functions, list comprehensions, and generator expressions.

Getting Started With Python’s min() and max() Functions

Python includes several built-in functions that make your life more pleasant and productive because they mean you don’t need to reinvent the wheel. Two examples of these functions are min() and max(). They mostly apply to iterables, but you can use them with multiple regular arguments as well. What’s their job? They take care of finding the smallest and largest values in their input data.

Whether you’re using Python’s min() or max(), you can use the function to achieve two slightly different behaviors. The standard behavior for each is to return the minimum or maximum value through straightforward comparison of the input data as it stands. The alternative behavior is to use a single-argument function to modify the comparison criteria before finding the smallest and largest values.

To explore the standard behavior of min() and max(), you can start by calling each function with either a single iterable as an argument or with two or more regular arguments. That’s what you’ll do right away.

Calling min() and max() With a Single Iterable Argument

The built-in min() and max() have two different signatures that allow you to call them either with an iterable as their first argument or with two or more regular arguments. The signature that accepts a single iterable argument looks something like this:

min(iterable, *[, default, key]) -> minimum_value

max(iterable, *[, default, key]) -> maximum_value

Both functions take a required argument called iterable and return the minimum and maximum values respectively. They also take two optional keyword-only arguments: default and key.

Here’s a summary of what the arguments to min() and max() do:

Argument Description Required
iterable Takes an iterable object, like a list, tuple, dictionary, or string Yes
default Holds a value to return if the input iterable is empty No
key Accepts a single-argument function to customize the comparison criteria No

Later in this tutorial, you’ll learn more about the optional default and key arguments. For now, just focus on the iterable argument, which is a required argument that leverages the standard behavior of min() and max() in Python:

>>>

>>> min([3, 5, 9, 1, -5])
-5

>>> min([])
Traceback (most recent call last):
    ...
ValueError: min() arg is an empty sequence

>>> max([3, 5, 9, 1, -5])
9

>>> max([])
Traceback (most recent call last):
    ...
ValueError: max() arg is an empty sequence

In these examples, you call min() and max() with a list of integer numbers and then with an empty list. The first call to min() returns the smallest number in the input list, -5. In contrast, the first call to max() returns the largest number in the list, or 9. If you pass an empty iterator to min() or max(), then you get a ValueError because there’s nothing to do on an empty iterable.

An important detail to note about min() and max() is that all the values in the input iterable must be comparable. Otherwise, you get an error. For example, numeric values work okay:

>>>

>>> min([3, 5.0, 9, 1.0, -5])
-5

>>> max([3, 5.0, 9, 1.0, -5])
9

These examples combine int and float numbers in the calls to min() and max(). You get the expected result in both cases because these data types are comparable.

However, what would happen if you mixed strings and numbers? Check out the following examples:

>>>

>>> min([3, "5.0", 9, 1.0, "-5"])
Traceback (most recent call last):
    ...
TypeError: '<' not supported between instances of 'str' and 'int'

>>> max([3, "5.0", 9, 1.0, "-5"])
Traceback (most recent call last):
    ...
TypeError: '>' not supported between instances of 'str' and 'int'

You can’t call min() or max() with an iterable of noncomparable types as an argument. In this example, a function tries to compare a number to a string, which is like comparing apples and oranges. The end result it that you get a TypeError.

Calling min() and max() With Multiple Arguments

The second signature of min() and max() allows you to call them with any number of arguments, provided that you use at least two arguments. This signature has the following form:

min(arg_1, arg_2[, ..., arg_n], *[, key]) -> minimum_value

max(arg_1, arg_2[, ..., arg_n], *[, key]) -> maximum_value

Again, these functions return the minimum and maximum values, respectively. Here’s the meaning of the arguments in the above signature:

Argument Description Required
arg_1, arg_2, ..., arg_n Accepts any number of regular arguments to compare Yes (at least two of them)
key Takes a single-argument function to customize the comparison criteria No

This variation of min() or max() doesn’t have a default argument. You must provide at least two arguments in the call for the function to work correctly. So, a default value isn’t required, because you’ll always have at least two values to compare in order to find the minimum or maximum.

To try out this alternative signature, run the following examples:

>>>

>>> min(3, 5, 9, 1, -5)
-5

>>> max(3, 5, 9, 1, -5)
9

You can call min() or max() with two or more regular arguments. Again, you’ll get the minimum or maximum value in the input data, respectively. The only condition is that the arguments must be comparable.

Using min() and max() With Strings and Iterables of Strings

By default, min() and max() can process values that are comparable. Otherwise, you get a TypeError, as you’ve already learned. Up to this point, you’ve seen examples that use numeric values either in an iterable or as multiple regular arguments.

Using min() and max() with numeric values is arguably the most common and useful use case of these functions. However, you can also use the functions with strings and iterables of strings. In these cases, the alphabetical order of characters will decide the final result.

For example, you can use min() and max() to find the smallest and largest letters in some text. In this context, smallest means closest to the beginning of the alphabet, and largest means closest to the end of the alphabet:

>>>

>>> min("abcdefghijklmnopqrstuvwxyz")
'a'

>>> max("abcdefghijklmnopqrstuvwxyz")
'z'

>>> min("abcdWXYZ")
'W'

>>> max("abcdWXYZ")
'd'

As promised, in the first two examples, min() returns 'a' and max() returns 'z'. However, in the second pair of examples, min() returns 'W' and max() returns 'd'. Why? Because uppercase letters come before lowercase letters in Python’s default character set, UTF-8.

Using min() or max() with a string as an argument isn’t limited to just letters. You can use strings containing any possible characters in your current character set. For example, if you’re working with the set of ASCII characters only, then the smallest character is the character closest to the beginning of the ASCII table. In contrast, the largest character is the character closest to the end of the table.

With other character sets like UTF-8, min() and max() behave similarly:

>>>

>>> # UTF-8 characters

>>> min("abc123ñ")
'1'

>>> max("abc123ñ")
'ñ'

Behind the scenes, min() and max() use the character’s numeric value to find the minimum and maximum characters in the input string. For example, in the Unicode character table, the uppercase A has a smaller numeric value than the lowercase a:

>>>

>>> ord("A")
65

>>> ord("a")
97

Python’s built-in ord() function takes a single Unicode character and returns an integer representing the Unicode code point of that character. In these examples, the code point for the uppercase "A" is lower than the code point for the lowercase "a".

This way, when you call min() and max() with both letters, you get results that match the order of the underlying Unicode code points of these letters:

>>>

>>> min("aA")
'A'

>>> max("aA")
'a'

What makes "A" smaller than "a"? The quick answer is the letter’s Unicode code point. All characters that you can type on your keyboard, and many other characters, have their own code points in the Unicode table. Python uses these code points to determine the minimum and maximum character when it comes to using min() and max().

Finally, you can also call min() and max() with iterables of strings or with multiple string arguments. Again, both functions will determine their return value by comparing the strings alphabetically:

>>>

>>> min(["Hello", "Pythonista", "and", "welcome", "world"])
'Hello'

>>> max(["Hello", "Pythonista", "and", "welcome", "world"])
'world'

To find the smallest or largest string in an iterable of strings, min() and max() compare all the strings alphabetically based on the code points of initial characters.

In the first example, the uppercase "H" comes before "P", "a", and "w" in the Unicode table. So, min() immediately concludes that "Hello" is the smallest string. In the second example, the lowercase "w" comes after all the other strings’ initial letters.

Note that there are two words that start with "w", "welcome" and "world". So, Python proceeds to look at the second letter of each word. The result is that max() returns "world" because "o" comes after "e".

Processing Dictionaries With min() and max()

When it comes to processing Python dictionaries with min() and max(), you need to consider that if you use the dictionary directly, then both functions will operate on the keys:

>>>

>>> prices = {
...    "banana": 1.20,
...    "pineapple": 0.89,
...    "apple": 1.57,
...    "grape": 2.45,
... }


>>> min(prices)
'apple'

>>> max(prices)
'pineapple'

In these examples, min() returns the alphabetically smallest key in prices, and max() returns the largest one. You can get the same result using the .keys() method on your input dictionary:

>>>

>>> min(prices.keys())
'apple'

>>> max(prices.keys())
'pineapple'

The only difference between this latter example and the previous one is that here, the code is more explicit and clear about what you’re doing. Anyone reading your code will quickly realize that you want to find the smallest and largest keys in the input dictionary.

Another common requirement would be to find the smallest and largest values in a dictionary. To continue with the prices example, say you want to know the smallest and largest prices. In this situation, you can use the .values() method:

>>>

>>> min(prices.values())
0.89

>>> max(prices.values())
2.45

In these examples, min() goes through all the values in prices and finds the minimum price. Similarly, max() iterates over the values of prices and returns the maximum price.

Finally, you can also use the .items() method on the input dictionary to find the minimum and maximum key-value pairs:

>>>

>>> min(prices.items())
('apple', 1.57)

>>> max(prices.items())
('pineapple', 2.45)

In this case, min() and max() use Python’s internal rules to compare tuples and find the smallest and largest items in the input dictionary.

Python compares tuples item by item. For example, to determine if (x1, x2) is greater than (y1, y2), Python tests x1 > y1. If this condition is True, then Python concludes that the first tuple is greater than the second without checking the rest of the items. In contrast, if x1 < y1, then Python concludes that the first tuple is less than the second.

Finally, if x1 == y1, then Python compares the second pair of items using the same rules. Note that in this context, the first item of each tuple comes from the dictionary keys, and because dictionary keys are unique, the items can’t be equal. So, Python will never have to compare the second values.

Tweaking the Standard Behavior of min() and max() With key and default

Up to this point, you’ve learned how min() and max() work in their standard form. In this section, you’ll learn how to tweak the standard behavior of both functions by using the key and default keyword-only arguments.

The key argument to min() or max() allows you to provide a single-argument function that will be applied to every value in the input data. The goal is to modify the comparison criteria to use in finding the minimum or maximum value.

As an example of how this feature can be useful, say that you have a list of numbers as strings, and want to find the smallest and largest numbers. If you process the list directly with min() and max(), then you get the following results:

>>>

>>> min(["20", "3", "35", "7"])
'20'

>>> max(["20", "3", "35", "7"])
'7'

These may not be the results that you need or expect. You’re getting the smallest and largest strings based on Python’s string comparison rules rather than based on the actual numeric value of each string.

In that case, the solution is to pass the built-in int() function as the key argument to min() and max(), like in the following examples:

>>>

>>> min(["20", "3", "35", "7"], key=int)
'3'

>>> max(["20", "3", "35", "7"], key=int)
'35'

Great! Now the result of min() or max() depends on the numeric values of the underlying strings. Note that you don’t need to call int(). You just pass int without the pair of parentheses because key expects a function object, or more accurately, a callable object.

The second keyword-only argument that allows you to customize the standard behavior of min() or max() is default. Remember that this argument is only available when you call the function with a single iterable as an argument.

The job of default is to provide a suitable default value as the return value of min() or max() when it’s called with an empty iterable:

>>>

>>> min([], default=42)
42

>>> max([], default=42)
42

In these examples, the input iterable is an empty list. The standard behavior is for min() or max() to raise a ValueError complaining about the empty sequence argument. However, because you supply a value to default, both functions now return this value instead of raising an exception and breaking your code.

Using min() and max() With Comprehensions and Generator Expressions

You can also call min() or max() with a list comprehension or generator expression as an argument. This feature comes in handy when you need to transform the input data right before finding the minimum or maximum transformed value.

When you feed a list comprehension into min() or max(), the resulting value will come from the transformed data rather than from the original data:

>>>

>>> letters = ["A", "B", "C", "X", "Y", "Z"]

>>> min(letters)
'A'
>>> min([letter.lower() for letter in letters])
'a'

>>> max(letters)
'Z'
>>> max([letter.lower() for letter in letters])
'z'

The second call to min() takes a list comprehension as an argument. This comprehension transforms the original data in letters by applying the .lower() method to each letter. The final result is the lowercase "a", which isn’t present in the original data. Something similar happens with the examples covering max().

Note that using min() or max() with a list comprehension is similar to using the key argument. The main difference is that with comprehensions, the final result is a transformed value, while with key, the result comes from the original data:

>>>

>>> letters = ["A", "B", "C", "X", "Y", "Z"]

>>> min([letter.lower() for letter in letters])
'a'

>>> min(letters, key=str.lower)
'A'

In both examples, min() uses .lower() to somehow modify the comparison criteria. The difference is that the comprehension actually transforms the input data before doing the computation, so the resulting value comes from the transformed data rather than from the original.

List comprehensions create a complete list in memory, which is often a wasteful operation. This fact holds especially true if you don’t need the resulting list in your code anymore, which could be the case with min() and max(). So, it’s always more efficient to use a generator expression instead.

The syntax for generator expressions is almost the same as for list comprehensions:

>>>

>>> letters = ["A", "B", "C", "X", "Y", "Z"]

>>> min(letters)
'A'
>>> min(letter.lower() for letter in letters)
'a'

>>> max(letters)
'Z'
>>> max(letter.lower() for letter in letters)
'z'

The main syntax difference is that a generator expression uses parentheses instead of square brackets ([]). Because a function call already requires parentheses, you just need to remove the square brackets from your comprehension-based examples, and you’re good to go. Unlike list comprehensions, generator expressions yield items on demand, which makes them memory efficient.

Putting Python’s min() and max() Into Action

So far, you’ve learned the basics of using min() and max() to find the smallest and largest values in an iterable or in a series of individual values. You learned how min() and max() work with different built-in Python data types, such as numbers, strings, and dictionaries. You also explored how to tweak the standard behavior of these functions and how to use them with list comprehensions and generator expressions.

Now you’re ready to start coding a few practical examples that will show you how to use min() and max() in your own code.

Removing the Smallest and Largest Numbers in a List

To kick things off, you’ll start with a short example of how to remove the minimum and maximum values from a list of numbers. To do that, you can call .remove() on your input list. Depending on your needs, you’ll use min() or max() to select the value that you’ll remove from the underlying list:

>>>

>>> sample = [4, 5, 7, 6, -12, 4, 42]

>>> sample.remove(min(sample))
>>> sample
[4, 5, 7, 6, 4, 42]

>>> sample.remove(max(sample))
>>> sample
[4, 5, 7, 6, 4]

In these examples, the minimum and maximum values in sample could be outlier data points that you want to remove so that they don’t affect your further analysis. Here, min() and max() provide the arguments to .remove().

Building Lists of Minimum and Maximum Values

Now say that you have a list of lists representing a matrix of numeric values, and you need to build lists containing the smallest and largest values from every row in the input matrix. To do this, you can use min() and max() along with a list comprehension:

>>>

>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> [min(x) for x in matrix]
[1, 4, 7]

>>> [max(x) for x in matrix]
[3, 6, 9]

The first comprehension iterates over the sublists in matrix and uses min() to build a list containing the smallest value from each sublist. The second comprehension does a similar task but uses max() to create a list containing the largest values from the sublists in matrix.

Even though min() and max() provide a quick way to deal with the examples in this section, the NumPy library is highly recommended when it comes to processing matrixes in Python because NumPy has specific and optimized tools for the job.

Clipping Values to the Edges of an Interval

Sometimes you have a list of numeric values and want to clip them to the edges or limits of a given interval. For example, if a given value is greater than the interval’s upper limit, then you need to convert it down to that limit. To do this operation, you can use min().

Wait! Why min()? You’re dealing with the large values, aren’t you? The point is that you need to compare each large value to the interval’s upper limit and then choose the smaller of the two. You’ll essentially set all large values to a prescribed upper limit:

>>>

>>> # Clip values to the largest interval's edge

>>> upper = 100
>>> numbers = [42, 78, 200, -230, 25, 142]

>>> [min(number, upper) for number in numbers]
[42, 78, 100, -230, 25, 100]

The call to min() compares every number to the interval’s upper limit. If the target number is greater than the limit, then min() returns the limit. The net effect is that all the values that are greater than the limit are now clipped to it. In this example, the numbers 200 and 142 are clipped to 100, which is the interval’s upper limit.

In contrast, if you want to clip small values to the interval’s lower limit, then you can use max(), like in the following example:

>>>

>>> # Clip values to the smallest interval's edge

>>> lower = 10
>>> numbers = [42, 78, 200, -230, 25, 142]

>>> [max(number, lower) for number in numbers]
[42, 78, 200, 10, 25, 142]

This call to max() clips the small values to the interval’s lower limit. To do this clipping, max() compares the current number and the interval’s limit to find the maximum value. In the example, -230 is the only number that gets clipped.

Finally, you can run both operations in one go by combining min() and max(). Here’s how to do it:

>>>

>>> # Clipping values to 10 - 100

>>> lower, upper = 10, 100
>>> numbers = [42, 78, 100, -230, 25, 142]

>>> [max(min(number, upper), lower) for number in numbers]
[42, 78, 100, 10, 25, 100]

To clip all the values that fall outside the interval’s limits, this comprehension combines min() and max(). The call to min() compares the current value to the interval’s upper limit, while the call to max() compares the result to the lower limit. The final result is that values lower than or greater than the corresponding limit are clipped to the limit itself.

This comprehension works similarly to the clip() function from NumPy, which takes an array and the limits of the target interval, then it clips all values outside the interval to the interval’s edges.

Finding the Closest Points

Now say that you have a list of tuples containing pairs of values that represent Cartesian points. You want to process all these pairs of points and find out which pair has the smallest distance between points. In this situation, you can do something like the following:

>>>

>>> import math

>>> point_pairs = [
...     ((12, 5), (9, 4)),
...     ((2, 5), (3, 7)),
...     ((4, 11), (15, 2))
... ]

>>> min(point_pairs, key=lambda points: math.dist(*points))
((2, 5), (3, 7))

In this example, you first import math to get access to dist(). This function returns the Euclidean distance between two points, p and q, each given as a sequence of coordinates. The two points must have the same number of dimensions.

The min() function works its magic through its key argument. In this example, key takes a lambda function that computes the distance between two points. This function becomes the comparison criteria for min() to find the pair of points with the minimal distance between points.

In this example, you need a lambda function because key expects a single-argument function, while math.dist() requires two arguments. So, the lambda function takes a single argument, points, and then unpacks it into two arguments to feed into math.dist().

Identifying Cheap and Expensive Products

Now say you have a dictionary with the names and prices of several products, and you want to identify the cheapest and most expensive products. In this situation, you can use .items() and an appropriate lambda function as the key argument:

>>>

>>> prices = {
...    "banana": 1.20,
...    "pineapple": 0.89,
...    "apple": 1.57,
...    "grape": 2.45,
... }

>>> min(prices.items(), key=lambda item: item[1])
('pineapple', 0.89)

>>> max(prices.items(), key=lambda item: item[1])
('grape', 2.45)

In this example, the lambda function takes a key-value pair as an argument and returns the corresponding value so that min() and max() have proper comparison criteria. As a result, you get a tuple with the cheapest and most expensive products in the input data.

Finding Coprime Integer Numbers

Another interesting example of using min() to solve a real-world problem is when you need to figure out if two numbers are coprime. In other words, you need to know if your numbers’ only common divisor is 1.

In that situation, you can code a Boolean-valued or predicate function like the following:

>>>

>>> def are_coprime(a, b):
...     for i in range(2, min(a, b) + 1):
...         if a % i == 0 and b % i == 0:
...             return False
...     return True
...

>>> are_coprime(2, 3)
True
>>> are_coprime(2, 4)
False

In this code snippet, you define are_coprime() as a predicate function that returns True if the input numbers are coprime. If the numbers aren’t coprime, then the function returns False.

The function’s main component is a for loop that iterates over a range of values. To set the upper limit for this range object, you use min() with the input numbers as arguments. Again, you’re using min() to set the upper limit of some interval.

Timing Different Implementations of Your Code

You can also use min() to compare several of your algorithms, evaluate their execution times, and determine which algorithm is the most efficient. The example below uses timeit.repeat() to measure the execution times for two different ways of building a list containing the square values of the numbers from 0 to 99:

>>>

>>> import timeit

>>> min(
...     timeit.repeat(
...         stmt="[i ** 2 for i in range(100)]",
...         number=1000,
...         repeat=3
...     )
... )
0.022141209003166296

>>> min(
...     timeit.repeat(
...         stmt="list(map(lambda i: i ** 2, range(100)))",
...         number=1000,
...         repeat=3
...     )
... )
0.023857666994445026

The call to timeit.repeat() runs a string-based statement a given number of times. In these examples, the statement is repeated three times. The call to min() returns the smallest execution time from the three repetitions.

By combining min(), repeat(), and other Python timer functions, you can get an idea of which of your algorithms is most efficient in terms of execution time. The example above shows that list comprehensions can be a little bit faster than the built-in map() function when it comes to building new lists.

Exploring the Role of .__lt__() and .__gt__() in min() and max()

As you’ve learned so far, the built-in min() and max() functions are versatile enough to work with values of various data types, such as numbers and strings. The secret behind this flexibility is that min() and max() embrace Python’s duck typing philosophy by relying on the .__lt__() and .__gt__() special methods.

These methods are part of what Python calls rich comparison methods. Specifically, .__lt__() and .__gt__() support the less than (<) and greater than (>) operators, respectively. What’s the meaning of support here? When Python finds something like x < y in your code, it internally does x.__lt__(y).

The takeaway is that you can use min() and max() with values of any data type that implements .__lt__() and .__gt__(). That’s why these functions work with values of all Python’s built-in data types:

>>>

>>> "__lt__" in dir(int) and "__gt__" in dir(int)
True

>>> "__lt__" in dir(float) and "__gt__" in dir(float)
True

>>> "__lt__" in dir(str) and "__gt__" in dir(str)
True

>>> "__lt__" in dir(list) and "__gt__" in dir(list)
True

>>> "__lt__" in dir(tuple) and "__gt__" in dir(tuple)
True

>>> "__lt__" in dir(dict) and "__gt__" in dir(dict)
True

Python’s built-in data types implement the .__lt__() and .__gt__() special methods. So, you can feed any of these data types into min() and max(), with the only condition being that the involved data types are comparable.

You can also make instances of your custom classes compatible with min() and max(). To achieve this, you need to provide your own implementations of .__lt__() and .__gt__(). Consider the following Person class as an example of this compatibility:

# person.py

from datetime import date

class Person:
    def __init__(self, name, birth_date):
        self.name = name
        self.birth_date = date.fromisoformat(birth_date)

    def __repr__(self):
        return (
            f"{type(self).__name__}"
            f"({self.name}, {self.birth_date.isoformat()})"
        )

    def __lt__(self, other):
        return self.birth_date > other.birth_date

    def __gt__(self, other):
        return self.birth_date < other.birth_date

Note that the implementation of .__lt__() and .__gt__() requires an argument that’s typically named other. This argument represents the second operand in the underlying comparison operations. For example, in an expression like x < y, you’ll have that x will be self and y will be other.

In this example, .__lt__() and .__gt__() return the result of comparing two people’s .birth_date attributes. Here’s how this works in practice:

>>>

>>> from person import Person

>>> jane = Person("Jane Doe", "2004-08-15")
>>> john = Person("John Doe", "2001-02-07")

>>> jane < john
True
>>> jane > john
False

>>> min(jane, john)
Person(Jane Doe, 2004-08-15)

>>> max(jane, john)
Person(John Doe, 2001-02-07)

Cool! You can process Person objects with min() and max() because the class provides implementation of .__lt__() and .__gt__(). The call to min() returns the youngest person, and the call to max() returns the oldest.

Note that if a given custom class doesn’t provide these methods, then its instances won’t support min() and max() operations:

>>>

>>> class Number:
...     def __init__(self, value):
...         self.value = value
...

>>> x = Number(21)
>>> y = Number(42)

>>> min(x, y)
Traceback (most recent call last):
    ...
TypeError: '<' not supported between instances of 'Number' and 'Number'

>>> max(x, y)
Traceback (most recent call last):
    ...
TypeError: '>' not supported between instances of 'Number' and 'Number'

Because this Number class doesn’t provide suitable implementations of .__lt__() and .__gt__(), min() and max() respond with a TypeError. The error message tells you that the comparison operations aren’t supported in your current class.

Emulating Python’s min() and max()

Up to this point, you’ve learned how Python’s min() and max() functions work. You’ve used them to find the smallest and largest values among several numbers, strings, and more. You know how to call these functions either with a single iterable as an argument or with an undefined number of regular arguments. Finally, you’ve coded a series of practical examples that approach real-world problems using min() and max().

Although Python kindly provides you with min() and max() to find the smallest and largest values in your data, learning how to do this computation from scratch is a helpful exercise that can improve your logical thinking and your programming skills.

In this section, you’ll learn how to find minimum and maximum values in your data. You’ll also learn how to implement your own versions of min() and max().

Understanding the Code Behind min() and max()

To find the minimum value in a small list of numbers as a human, you’d normally check the numbers and implicitly compare all of them in your mind. Yes, your brain is amazing! However, computers aren’t that smart. They need detailed instructions to accomplish any task.

You’ll have to tell your computer to iterate over all the values while comparing them in pairs. In the process, the computer has to take note of the current minimum value in each pair until the list of values is processed entirely.

This explanation may be hard to visualize, so here’s a Python function that does the work:

>>>

>>> def find_min(iterable):
...     minimum = iterable[0]
...     for value in iterable[1:]:
...         if value < minimum:
...             minimum = value
...     return minimum
...

>>> find_min([2, 5, 3, 1, 9, 7])
1

In this code snippet, you define find_min(). This function assumes that iterable isn’t empty and that its values are in an arbitrary order.

The function treats the first value as a tentative minimum. Then the for loop iterates over the rest of the elements in the input data.

The conditional statement compares the current value to the tentative minimum in the first iteration. If the current value is smaller than minimum, then the conditional updates minimum accordingly.

Each new iteration compares the current value to the updated minimum. When the function reaches the end of iterable, minimum will hold the smallest value in the input data.

Cool! You’ve coded a function that finds the smallest value in an iterable of numbers. Now revisit find_min() and think of how you’d code a function to find the largest value. Yes, that’s it! You just have to change the comparison operator from less than (<) to greater than (>), and probably rename the function and some local variables to prevent confusion.

Your new function can look something like this:

>>>

>>> def find_max(iterable):
...     maximum = iterable[0]
...     for value in iterable[1:]:
...         if value > maximum:
...             maximum = value
...     return maximum
...

>>> find_max([2, 5, 3, 1, 9, 7])
9

Note that find_max() shares most of its code with find_min(). The most important difference, apart from naming, is that find_max() uses the greater than operator (>) instead of the less than operator (<).

As an exercise, you can think of how to avoid repetitive code in find_min() and find_max() following the DRY (don’t repeat yourself) principle. This way, you’ll be ready to emulate the complete behavior of min() and max() using your Python skills, which you’ll tackle in just a moment.

Before diving in, you need to be aware of the knowledge requirements. You’ll be combining topics like conditional statements, exception handling, list comprehensions, definite iteration with for loops, and *args and optional arguments in functions.

If you feel that you don’t know everything about these topics, then don’t worry. You’ll learn by doing. If you get stuck, then you can go back and review the linked resources.

Planning Your Custom min() and max() Versions

To write your custom implementations of min() and max(), you’ll start by coding a helper function that’s able to find the smallest or largest value in the input data, depending on the arguments you use in the call. Of course, the helper function will especially depend on the operator used for comparing the input values.

Your helper function will have the following signature:

min_max(*args, operator, key=None, default=None) -> extreme_value

Here’s what each argument does:

Argument Description Required
*args Allows you to call the function with either an iterable or any number of regular arguments Yes
operator Holds the appropriate comparison operator function for the computation at hand Yes
key Takes a single-argument function that modifies the function’s comparison criteria and behavior No
default Stores a default value to return when you call the function with an empty iterable No

The body of min_max() will start by processing *args to build a list of values. Having a standardized list of values will allow you to write the required algorithm to find the minimum and maximum values in the input data.

Then the function needs to deal with the key and default arguments before computing the minimum and maximum, which is the final step inside min_max().

With min_max() in place, the final step is to define two independent functions on top of it. These functions will use appropriate comparison operator functions to find the minimum and maximum values, respectively. You’ll learn more about operator functions in a moment.

Standardizing the Input Data From *args

To standardize the input data, you need to check if the user is providing a single iterable or any number of regular arguments. Fire up your favorite code editor or IDE and create a new Python file called min_max.py. Then add the following piece of code to it:

# min_max.py

def min_max(*args, operator, key=None, default=None):
    if len(args) == 1:
        try:
            values = list(args[0])  # Also check if the object is iterable
        except TypeError:
            raise TypeError(
                f"{type(args[0]).__name__} object is not iterable"
            ) from None
    else:
        values = args

Here, you define min_max(). The function’s first portion standardizes the input data for further processing. Because the user will be able to call min_max() with either a single iterable or with several regular arguments, you need to check the length of args. To do this check, you use the built-in len() function.

If args holds only one value, then you need to check if that argument is an iterable object. You use list(), which implicitly does the check and also turns the input iterable into a list.

If list() raises a TypeError, then you catch it and raise your own TypeError to inform the user that the provided object isn’t iterable, just like min() and max() do in their standard form. Note that you use the from None syntax to hide away the traceback of the original TypeError.

The else branch runs when args holds more than one value, which handles the cases where the user calls the function with several regular arguments instead of with a single iterable of values.

If this conditional doesn’t ultimately raise a TypeError, then values will hold a list of values that may be empty. Even if the resulting list is empty, it’s now clean and ready for continuing the process of finding its minimum or maximum value.

Processing the default Argument

To continue writing min_max(), you can now process the default argument. Go ahead and add the following code to the end of the function:

# min_max.py
# ...

def min_max(*args, operator, key=None, default=None):
    # ...

    if not values:
        if default is None:
            raise ValueError("args is an empty sequence")
        return default

In this code snippet, you define a conditional to check if values holds an empty list. If that’s the case, then you check the default argument to see if the user provided a value for it. If default is still None, then a ValueError is raised. Otherwise, default gets returned. This behavior emulates the standard behavior of min() and max() when you call them with empty iterables.

Handling the Optional key Function

Now you need to process the key argument and prepare the data for finding the smallest and largest values according to the provided key. Go ahead and update min_max() with the following code:

# min_max.py
# ...

def min_max(*args, operator, key=None, default=None):
    # ...

    if key is None:
        keys = values
    else:
        if callable(key):
            keys = [key(value) for value in values]
        else:
            raise TypeError(f"{type(key).__name__} object is not a callable")

You start this code fragment with a conditional that checks if the user hasn’t provided a key function. If they haven’t, then you create a list of keys directly from your original values. You’ll use these keys as comparison keys in computing the minimum and maximum.

On the other hand, if the user has provided a key argument, then you need to make sure that the argument is actually a function or callable object. To do this, you use the built-in callable() function, which returns True if its argument is a callable and False otherwise.

Once you’re sure that key is a callable object, then you build the list of comparison keys by applying key to each value in the input data.

Finally, if key isn’t a callable object, then the else clause runs, raising a TypeError, just like min() and max() do in a similar situation.

Finding Minimum and Maximum Values

The last step to finish your min_max() function is to find the minimum and maximum values in the input data, just like min() and max() do. Go ahead and wrap up min_max() with the following code:

# min_max.py
# ...

def min_max(*args, operator, key=None, default=None):
    # ...

    extreme_key, extreme_value = keys[0], values[0]
    for key, value in zip(keys[1:], values[1:]):
        if operator(key, extreme_key):
            extreme_key = key
            extreme_value = value
    return extreme_value

You set the extreme_key and extreme_value variables to the first value in keys and in values, respectively. These variables will provide the initial key and value for computing the minimum and maximum.

Then you loop over the remaining keys and values in one go using the built-in zip() function. This function will yield key-value tuples by combining the values in your keys and values lists.

The conditional inside the loop calls operator to compare the current key to the tentative minimum or maximum key stored in extreme_key. At this point, the operator argument will hold either lt() or gt() from the operator module, depending on if you want to find the minimum or maximum value, respectively.

For example, when you want to find the smallest value in the input data, operator will hold the lt() function. When you want to find the largest value, operator will hold gt().

Every loop iteration compares the current key to the tentative minimum or maximum key and updates the values of extreme_key and extreme_value accordingly. At the end of the loop, these variables will hold the minimum or maximum key and its corresponding value. Finally, you just need to return the value in extreme_value.

Coding Your Custom min() and max() Functions

With the min_max() helper function in place, you can define your custom versions of min() and max(). Go ahead and add the following functions to the end of your min_max.py file:

# min_max.py

from operator import gt, lt

# ...

def custom_min(*args, key=None, default=None):
    return min_max(*args, operator=lt, key=key, default=default)

def custom_max(*args, key=None, default=None):
    return min_max(*args, operator=gt, key=key, default=default)

In this code snippet, you first import gt() and lt() from the operator module. These functions are the functional equivalent of the greater than (>) and less than (<) operators, respectively. For example, the Boolean expression x < y is equivalent to the function call lt(x, y). You’ll use these functions to provide the operator argument to your min_max().

Just like min() and max(), custom_min() and custom_max() take *args, key, and default as arguments and return the minimum and maximum values, respectively. To perform the computation, these functions call min_max() with the required arguments and with the appropriate comparison operator function.

In custom_min(), you use lt() to find the smallest value in the input data. In custom_max(), you use gt() to get the largest value.

Click the collapsible section below if you want to get the entire content of your min_max.py file:

# min_max.py

from operator import gt, lt

def min_max(*args, operator, key=None, default=None):
    if len(args) == 1:
        try:
            values = list(args[0])  # Also check if the object is iterable
        except TypeError:
            raise TypeError(
                f"{type(args[0]).__name__} object is not iterable"
            ) from None
    else:
        values = args

    if not values:
        if default is None:
            raise ValueError("args is an empty sequence")
        return default

    if key is None:
        keys = values
    else:
        if callable(key):
            keys = [key(value) for value in values]
        else:
            raise TypeError(f"{type(key).__name__} object is not a callable")

    extreme_key, extreme_value = keys[0], values[0]
    for key, value in zip(keys[1:], values[1:]):
        if operator(key, extreme_key):
            extreme_key = key
            extreme_value = value
    return extreme_value

def custom_min(*args, key=None, default=None):
    return min_max(*args, operator=lt, key=key, default=default)

def custom_max(*args, key=None, default=None):
    return min_max(*args, operator=gt, key=key, default=default)

Cool! You’ve finished coding your own versions of min() and max() in Python. Now go ahead and give them a try!

Conclusion

Now you know how to use Python’s built-in min() and max() functions to find the smallest and largest values in an iterable or in a series of two or more regular arguments. You also learned about a few other characteristics of min() and max() that can make them useful in your day-to-day programming.

In this tutorial, you learned how to:

  • Find the smallest and largest values using Python’s min() and max(), respectively
  • Call min() and max() with a single iterable and with several regular arguments
  • Use min() and max() with strings and dictionaries
  • Customize the behavior of min() and max() with key and default
  • Feed comprehensions and generator expressions into min() and max()

Additionally, you’ve coded a handful of practical examples using min() and max() to approach real-world problems that you might run into while coding. You’ve also a written custom version of min() and max() in pure Python, a nice learning exercise that helped you understand the logic behind these built-in functions.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Mavic mini ошибка 30246
  • Mavic mini ошибка 30008