Iterables and iterators

INPUT · Slides

Walking two rows together

01 / 06

You want to match two rows up

You have a list of names and a list of scores, kept separately, and you want to show "Yui got 90".

With enumerate from the last lesson you can do it by looking one up by number. But the number showing through costs the reader a moment.

names = ["Yui", "Sou"]scores = [90, 60]for i, name in enumerate(names):    print(name, scores[i])

Result

Yui 90
Sou 60

02 / 06

zip lines them up side by side

The plain way to write it is zip. Same word as the fastener on a coat, and the picture is right: the teeth of two rows meshing together.

Write for name, score in zip(names, scores): and each turn brings you one from each. No number appears anywhere.

names = ["Yui", "Sou"]scores = [90, 60]for name, score in zip(names, scores):    print(f"{name} got {score}")

Result

Yui got 90
Sou got 60

03 / 06

Inside it is a row of pairs

What zip hands out is a tuple too, just as enumerate did. Show it as it is and you see nothing useful.

print(zip(names, scores))<zip object at 0x1234abcd>

Put it through list and every meshed pair is visible. The first of the left row is paired with the first of the right, as you would hope.

names = ["Yui", "Sou"]scores = [90, 60]print(list(zip(names, scores)))

Result

[('Yui', 90), ('Sou', 60)]

04 / 06

It stops with the shorter one

What if the lengths differ? It ends where the shorter one runs out, and there is no error.

Below there are three names and two scores. The third, Aoi, never appears. Nothing complains, so dropping data by accident is easy to miss.

If you zip things that ought to be the same length, check that they are and sleep better.

names = ["Yui", "Sou", "Aoi"]scores = [90, 60]for name, score in zip(names, scores):    print(name, score)

Result

Yui 90
Sou 60

05 / 06

Three rows, or more

You are not limited to two rows. Hand zip three and you take three names.

Mixing a list with a string is fine as well. Anything iterable can be lined up — the lid you opened at the start of the chapter pays off here.

names = ["Yui", "Sou"]scores = [90, 60]grades = ["A", "C"]for name, score, grade in zip(names, scores, grades):    print(name, score, grade)

Result

Yui 90 A
Sou 60 C

06 / 06

The chapter in short

Almost nothing new became possible in this chapter. What you got instead was a look at the inside of the for you had been using all along.

  • a thing you can loop over is an iterable
  • the thing that hands them out one at a time is an iterator
  • for is only iter and next, over and over
  • want the position, enumerate; want two rows together, zip

enumerate and zip are the two where knowing them changes how your code looks. When you feel the urge to add to a counter yourself, think of these two first.

Next chapter you learn to build a new list out of an old one in a single line.