Ready-made iterator building blocks: endless counters, cycles, chains, slices and combinations.
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.
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
from itertools import repeat
# repeat value
list(repeat(10, 3))
# ans: [10, 10, 10]
Without a count, repeat(10) goes on forever.
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.
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.
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.
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.
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.
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.
Predict the answer, then press → to check.
from itertools import count
# count is infinite?
c = count()
next(c)
# ans: 0
next(c)
# ans: 1
# ans: never stops
from itertools import cycle
# cycle repeats?
c = cycle([1, 2])
[next(c) for _ in range(5)]
# ans: [1, 2, 1, 2, 1]
from itertools import repeat, islice
# repeat without count?
r = repeat(5)
# ans: infinite
list(islice(r, 3))
# ans: [5, 5, 5]
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.
from itertools import islice
# islice with step?
list(islice(range(20), 0, 10, 2))
# ans: [0, 2, 4, 6, 8]
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.
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)]
from itertools import combinations
# combinations order?
list(combinations([3, 1, 2], 2))
# ans: [(3, 1), (3, 2), (1, 2)]
# ans: maintains input order
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.
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'.
count, cycle, repeat: pair them with break or islice.
chain, islice, groupby, zip_longest reshape streams lazily.
product (all pairs), permutations (order matters), combinations (it doesn't).