Using min, max, sum

Concepts covered: Math Ops

Three built-in functions answer the first questions anyone asks about a column of numbers. sum adds every item, min returns the smallest and max returns the largest. Each takes a whole collection, walks through it and returns 1 value, replacing a loop and a running variable with a single call.

splits = (312, 298, 305, 291, 284)

print(sum(splits))
print(min(splits))
print(max(splits))
print(max(splits) - min(splits))
print(sum(splits) / len(splits))

Output:

1490
284
312
28
298.0

The last 2 lines are the usual combinations: the spread between the slowest and fastest kilometre, and the average split. Division with / always produces a float, which is why the average prints as 298.0. Written out by hand, the work behind sum and min looks like this:

splits = (312, 298, 305, 291, 284)

total = 0
for s in splits:
    total = total + s

fastest = splits[0]
for s in splits:
    if s < fastest:
        fastest = s

The 2 loops start differently. A total can start at 0 before any item is seen, while a minimum has to start from a real item, since no number is guaranteed to be larger than all of them. That difference decides what an empty collection does, further down.

Any collection, or loose arguments

All 3 accept anything you can loop over: a list, a tuple, a set or a range. min and max also accept 2 or more separate values, which suits picking the larger of 2 readings. sum takes the collection as its first argument, so sum(140, 152) raises a TypeError.

paces = [312, 298, 305]
distinct_km = {5, 10, 5, 21}

print(max(paces), min(distinct_km))
print(sum(range(1, 6)))
print(max(140, 152))
print(min(185, 210, 199))

Output:

312 5
15
152
185

Strings and dictionaries compare differently

min and max work on anything that < can compare. Strings compare character by character in character-code order, where every uppercase letter sorts before every lowercase one. A dictionary passed to min or max is compared by its keys, so the answer is a key and the values play no part.

cities = ["lisbon", "Porto", "faro"]
print(min(cities))
print(max(cities))

best_km = {"ana": 21, "ben": 42, "caro": 10}
print(max(best_km))
print(min(best_km))

Output:

Porto
lisbon
caro
ana

max(best_km) returns caro because c is the latest letter among the keys, though Caro ran the shortest distance. When you want the largest number, pass the numbers. The lesson on dictionary views, later in the track, shows the direct way to hand a dictionary's values to max.

Empty collections and mixed types

An empty collection splits the 3 functions apart. sum starts at 0, finds nothing to add and returns 0. min and max have no item to start from, so they raise an error. A day with no uploads is ordinary input for a daily job, so this case reaches real code.

todays_splits = []
print(sum(todays_splits))
print(max(todays_splits, default=0))

Output:

0
0

Without default, max(todays_splits) stops the program with ValueError: max() arg is an empty sequence. The default keyword argument gives min and max a value to return when the collection is empty. Choose one that cannot be mistaken for real data, or check the length first and skip the summary. default works only with a single collection; combined with loose arguments it raises a TypeError.

Mixed types fail as well. sum adds with +, so a string among the numbers raises TypeError: unsupported operand type(s) for +: 'int' and 'str'. min and max compare with <, so min([312, "298"]) raises TypeError: '<' not supported between instances of 'str' and 'int'. A split stored as text must become a number first, which the Type Conversions lesson covers.

A daily job receives a runner's splits for a day with no uploads. What does this program print?

splits = []
print(sum(splits), max(splits, default=-1))

Counting with sum

In arithmetic Python treats True as 1 and False as 0. Summing a list of comparison results therefore counts how many were true, here the kilometres run in under 5 minutes.

splits = (312, 298, 305, 291, 284)
fast = []
for s in splits:
    fast.append(s < 300)

print(fast)
print(sum(fast))

Output:

[False, True, False, True, True]
3
Do
  • Pass default= to min and max when the input can be empty
  • Check the length before computing sum(x) / len(x)
  • Pass the numbers themselves to max when you want the largest number
Avoid
  • Don't write a running-total loop where sum does the job
  • Don't feed numbers stored as text into sum, min or max
  • Don't expect max(some_dict) to look at the values

About this lesson

This section is part of the Collections: Beginner lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.