It’s often necessary to iterate over multiple lists simultaneously. Suppose we’re keeping score of a game and we have two lists, one for names and one for scores:
>>> names = ["Bob", "Alice", "Eve"]
>>> scores = [42, 97, 68]
The zip
function takes any number of iterable arguments and steps through
all of them at the same time until the end of the shortest iterable has been reached:
>>> for name, score in zip(names, scores):
>>> print(f"{name} had a score of {score}.")
...
Bob had a score of 42.
Alice had a score of 97.
Eve had a score of 68.
What will the above loop print after removing the last element from scores
?
>>> scores.pop(-1)
68
>>> for name, score in zip(names, scores):
>>> print(f"{name} had a score of {score}.")
...
Bob had a score of 42.
Alice had a score of 97.
The loop terminates even though there are more values in names
. Here, Eve isn’t included because scores
only has two elements.
We can also use zip()
to quickly and easily create a dict
from two lists.
>>> names = ["Bob", "Alice", "Eve"]
>>> scores = [42, 97, 68]
>>> score_dict = dict(zip(names, scores))
>>> print(score_dict)
{'Bob': 42, 'Alice': 97, 'Eve': 68}
Note that the result of calling the zip function is actually a generator under the hood. You can only loop over the result of zipping once. If you try to loop over it again, the result will be empty.
>>> names = ["Bob", "Alice", "Eve"]
>>> scores = [42, 97, 68]
>>> zip_result = zip(names, scores)
# Works fine the first time!
>>> for name, score in zip_result:
... print(f"{name} had a score of {score}.")
...
Bob had a score of 42.
Alice had a score of 97.
Eve had a score of 68.
# But empty if we try to loop over it again.
>>> for name, score in zip_result:
... print(f"{name} had a score of {score}.")
...
>>>