Python · iterators & generators

Itertools

Ready-made iterator building blocks: endless counters, cycles, chains, slices and combinations.

count


          from itertools import count
          # infinite counting
          for i in count(10, 2):
              print(i)
              if i > 20:
                  break
          # ans: 10, 12, 14, 16, 18, 20, 22
        

22 is printed before the check, so it appears too. Without the break, this would never end.

cycle


          from itertools import cycle
          # infinite cycling
          colors = ['red', 'green', 'blue']
          color_cycle = cycle(colors)
          for i, color in enumerate(color_cycle):
              print(color)
              if i >= 5:
                  break
          # ans: red, green, blue, red, green, blue
        

repeat


          from itertools import repeat
          # repeat value
          list(repeat(10, 3))
          # ans: [10, 10, 10]
        

Without a count, repeat(10) goes on forever.

chain


          from itertools import chain
          # combine iterables
          list(chain([1, 2], [3, 4], [5, 6]))
          # ans: [1, 2, 3, 4, 5, 6]
        

One iterable after another, without building a combined list first.

islice


          from itertools import islice
          # slice iterator: islice(it, start, stop, step)
          list(islice(range(10), 2, 8, 2))
          # ans: [2, 4, 6]
        

Like list slicing, but for any iterator: it stops at stop without looking further.

islice: take the first n


          from itertools import islice, count
          # take first n
          list(islice(count(), 5))
          # ans: [0, 1, 2, 3, 4]
        

This works even on an infinite iterator like count(): only 5 values are ever made.

product


          from itertools import product
          # cartesian product
          list(product([1, 2], ['a', 'b']))
          # ans: [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
        

Every row with every column: like nested for loops.

permutations


          from itertools import permutations
          # all orderings
          list(permutations([1, 2, 3], 2))
          # ans: [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
        

Order matters, so (1, 2) and (2, 1) both appear; an item can't pair with itself.

combinations


          from itertools import combinations
          # unique selections
          list(combinations([1, 2, 3, 4], 2))
          # ans: [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
        

Order doesn't matter: only the upper triangle, each pair once.

Exercises

Predict the answer, then press → to check.

Exercise 1


          from itertools import count
          # count is infinite?
          c = count()
          next(c)
          # ans: 0
          next(c)
          # ans: 1
          # ans: never stops
        

Exercise 2


          from itertools import cycle
          # cycle repeats?
          c = cycle([1, 2])
          [next(c) for _ in range(5)]
          # ans: [1, 2, 1, 2, 1]
        

Exercise 3


          from itertools import repeat, islice
          # repeat without count?
          r = repeat(5)
          # ans: infinite
          list(islice(r, 3))
          # ans: [5, 5, 5]
        

Exercise 4


        from itertools import chain
        # chain vs +?
        chain([1], [2], [3])
        # ans: an iterator
        [1] + [2] + [3]
        # ans: [1, 2, 3] (a list)
      

+ builds a new list right away; chain hands out the items lazily.

Exercise 5


          from itertools import islice
          # islice with step?
          list(islice(range(20), 0, 10, 2))
          # ans: [0, 2, 4, 6, 8]
        

Exercise 6


        from itertools import product
        # product with repeat?
        list(product([0, 1], repeat=3))
        # ans: [(0,0,0), (0,0,1), (0,1,0), (0,1,1),
        # ans:  (1,0,0), (1,0,1), (1,1,0), (1,1,1)]
      

repeat=3 means product([0, 1], [0, 1], [0, 1]): all 8 three-bit patterns, counting in binary.

Exercise 7


          from itertools import permutations, combinations
          # permutations vs combinations?
          list(permutations([1, 2], 2))
          # ans: [(1, 2), (2, 1)]
          list(combinations([1, 2], 2))
          # ans: [(1, 2)]
        

Exercise 8


          from itertools import combinations
          # combinations order?
          list(combinations([3, 1, 2], 2))
          # ans: [(3, 1), (3, 2), (1, 2)]
          # ans: maintains input order
        

Exercise 9


          from itertools import groupby
          # group consecutive
          data = [1, 1, 2, 2, 2, 3]
          [(k, list(g)) for k, g in groupby(data)]
          # ans: [(1, [1, 1]), (2, [2, 2, 2]), (3, [3])]
        

groupby only groups neighbouring equal items; sort first to group all equal values.

Exercise 10


          from itertools import zip_longest
          # zip with fillvalue
          list(zip_longest([1, 2], ['a', 'b', 'c'], fillvalue=0))
          # ans: [(1, 'a'), (2, 'b'), (0, 'c')]
        

Plain zip would stop at the shorter list and drop 'c'.

Remember

Infinite

count, cycle, repeat: pair them with break or islice.

Plumbing

chain, islice, groupby, zip_longest reshape streams lazily.

Combinatorics

product (all pairs), permutations (order matters), combinations (it doesn't).