Comparing Lists
Concepts covered: Sorting
Two lists are equal when they have the same length and every pair of items in matching positions is equal. Python starts at position 0 of both lists and moves forward one position at a time until it finds a pair that differs. Order counts: [1, 2, 3] == [3, 2, 1] is False because position 0 holds 1 on the left and 3 on the right.
expected = ["id", "name", "email"]
received = ["id", "name", "email"]
shuffled = ["id", "email", "name"]
print(expected == received)
print(expected == shuffled)
print(expected is received)
print([1, 2] == [1, 2, 0])
print([1] == ["1"])Output:
True False False False False
A pipeline uses == this way to check a file's header against the columns it expects. shuffled holds the right names in the wrong order and fails the check, which is what you want when columns are read by position. is asks a different question. As with None, it tests whether 2 names refer to the same object. Here expected and received are separate lists that happen to hold equal items. Compare contents with ==. The last line shows that the integer 1 and the string "1" are unequal, and comparing them raises no error.
Which list sorts first
< and <= use the same walk, as do > and >=. Python finds the first position where the items differ, and that single pair decides the whole comparison; everything after it is ignored. Strings compare the same way: "apple" < "apricot" is settled at the third letter, where p comes before r.
def compare(left, right):
i = 0
while i < len(left) and i < len(right):
a = left[i]
b = right[i]
if a != b:
print(f"position {i}: {a} vs {b}")
return a < b
i += 1
print("shared positions match; shorter is smaller")
return len(left) < len(right)
print(compare([3, 9, 1], [3, 10, 0]))
print(compare([2, 5], [2, 5, 0]))
print([3, 9, 1] < [3, 10, 0])position 1: 9 vs 10 True shared positions match; shorter is smaller True True
The function in the animation does by hand what < does for you. In the first call, position 0 holds 3 on both sides, position 1 holds 9 against 10, and 9 is smaller, so the left list sorts first. The trailing 1 and 0 are never looked at. In the second call every shared position matches, so length breaks the tie: a list that is the start of a longer list sorts before it.
| Comparison | Deciding position | Result |
|---|---|---|
| `[2, 9] < [3, 0]` | 0: 2 vs 3 | True |
| `[5, 1, 7] < [5, 1, 4]` | 2: 7 vs 4 | False |
| `[4, 4] < [4, 4, 1]` | None; left is shorter | True |
| `[4, 4] < [4, 4]` | None; same length | False |
| `[4, 4] <= [4, 4]` | None; equal lists | True |
| `[] < [0]` | None; left is shorter | True |
Version numbers: lists beat strings
print("3.9.1" < "3.10.0")
print([3, 9, 1] < [3, 10, 0])
releases = [[3, 10, 0], [3, 9, 1], [2, 7, 18], [3, 9, 0]]
releases.sort()
print(releases)Output:
False True [[2, 7, 18], [3, 9, 0], [3, 9, 1], [3, 10, 0]]
Compared as strings, "3.9.1" and "3.10.0" first differ at the third character. There 9 meets 1, and because the character 9 is larger, the string comparison calls 3.9.1 the newer release. Stored as lists of integers, the same versions compare 9 against 10 and come out right. The sort() method rearranges a list from smallest to largest by applying < to its items, so a list of version lists lands in release order with no extra code. Dates stored as [year, month, day] sort correctly for the same reason.
When items cannot be compared
Python compares only up to the deciding position, so types further along never meet. [1, "x"] < [2, 0] is True: position 0 settles it before "x" faces 0. If the first items match, as they do in [1, "x"] < [1, 0], Python has to compare a string with an integer at position 1. That raises TypeError: '<' not supported between instances of 'str' and 'int'. == never raises this way, because items of different types count as unequal.
Which line raises a TypeError?
a = [0, "late"] < [1, "ok"]
b = [0, "late"] == [0, 7]
c = [0, "late"] < [0, 7]
d = ["0", 5] < ["0", 6]- Line a, because a string sits at position 1 of the left list
- Line b, because == cannot compare a string with an integer
- Line d, because a string is compared before the integers
- Line c, because position 0 ties and position 1 meets str and int
About this lesson
This section is part of the Lists: Intermediate 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.