Course outline · 0% complete

0/32 lessons0%

Course overview →

Working Over a Whole List

lesson 6-3 · ~12 min · 19/32

Built-ins that eat a whole list

Totals, averages, biggest and smallest: every report, invoice, and dashboard boils a list down to a few numbers. The loops for these are so common that Python ships them as built-in functions, so the hand-written loop disappears.

Python ships helpers so common loops disappear:

scores = [85, 92, 78, 90, 88]
sum(scores)      # 433
min(scores)      # 78
max(scores)      # 92
len(scores)      # 5
sorted(scores)   # [78, 85, 88, 90, 92]  new list

Sorting has a famous trap. sorted(lst) returns a new sorted list. lst.sort() sorts in place and returns None. So:

nums = [3, 1, 2]
nums = nums.sort()   # BUG: nums is now None

Either call nums.sort() on its own line, or use nums = sorted(nums). Never mix the two styles.

Built-ins replacing hand-written loops

Five lines here do work that lesson 5-3 did by hand. The middle pair is the one to watch, since it shows what sorted does and does not touch.

scores = [85, 92, 78, 90, 88]
print(max(scores))
print(sorted(scores))
print(scores)
avg = sum(scores) / len(scores)
print(f"average: {avg:.1f}")

Output

92
[78, 85, 88, 90, 92]
[85, 92, 78, 90, 88]
average: 86.6

The second line prints a sorted list and the third prints the original still in its arrival order, which proves sorted built something new rather than rearranging scores. The average combines two built-ins, sum for the total and len for the number of items, and because / produces a float the result carries decimals. The :.1f spec then trims the display to one decimal place without altering the stored value.

This snippet prints None.

nums = [3, 1, 2]
nums = nums.sort()
print(nums)

The list really was sorted, but sort() does its work in place and hands back None to signal that it returned nothing useful. The assignment then overwrites nums with that None, discarding the sorted list entirely.

This bug is nasty because the failure surfaces later, usually as an error complaining that None is not subscriptable. The two correct forms are nums.sort() on a line by itself, or nums = sorted(nums), and the rule is simply never to assign the result of a method that sorts in place.

Filter and build together

This is the most common list pattern in working code: walk a collection and build a new one holding only the items that pass a test. Search results, permission checks, and report filters are all this shape with larger data.

scores = [85, 92, 78, 90, 88, 65]
passing = []
for s in scores:
    if s >= 80:
        passing.append(s)
print(passing)
print(len(passing))

Output

[85, 92, 90, 88]
4

The loop visits all six scores and appends four of them, so the source list is left intact and the result is a separate, shorter list. Order is preserved from the original, since items are appended as they are encountered. Calling len on the result then answers how many passed, which is why the filter and the count do not need separate loops.

A single loop can maintain several accumulators, which is how you get a total and an extreme value in one pass. Interviewers ask for exactly this.

nums = [4, 11, 7, 2, 9]
total = 0
biggest = nums[0]
for n in nums:
    total += n
    if n > biggest:
        biggest = n
print(total, biggest)

Output

33 11

The two accumulators start differently on purpose. A sum begins at 0 because that is the total of nothing, but a maximum cannot begin at 0, since a list of negative numbers would then report a maximum no member actually has. Seeding biggest with nums[0] avoids that by starting from a real value. Inside the loop the total grows unconditionally while biggest is replaced only when a larger value appears, and one pass over the data settles both answers.

This snippet prints [1, 2, 5].

nums = [3, 1, 2]
nums.append(5)
nums.pop(0)
print(nums)

The append puts 5 at the end, making the list [3, 1, 2, 5]. Then pop(0) removes the item at the front, which is the 3, and the remaining three items close the gap.

That closing of the gap has a cost. Every item after the removed one shifts down by one index, so removing from the front of a long list is measurably slower than removing from the back, where nothing needs to move. It is a small detail on a four-item list and a real performance consideration on a list of a million.