Share @ Google LinkedIn Facebook  itertools, iterators, common_iterators

Overview

It provides list of iterator for some common tasks like permutations, combinations, infinite iterators, cycle looping etc.

In [1]:
import itertools
from datetime import datetime
import time

Infinite Iterators:

  • count(start=0,step=1) - Keeps on increasing count by step from start until loop is stopped by some condition.
  • cycle(iterable) - keeps on looping through iterable infinite times. After last element has used it again starts from first one like cycle.
  • repeat(object[,times=None]) - Keeps on repeating object infinite times until stopped by some loop. If times is provided as some integer then it repeats that many times.
In [2]:
result = []
for i in itertools.count(5, 5):
    if i <= 100:
        result.append(i)
    else:
        break
print(result)

result = []
for i in itertools.cycle(range(1,6)):
    if len(result) < 15:
        result.append(i)
    else:
        break
print(result)

result = []
for i in itertools.cycle(['B','O','B']):
    if len(result) < 15:
        result.append(i)
    else:
        break
print(result)

print(list(itertools.repeat('A', 5)))
print(list(itertools.repeat([1,2], 5)))
print(list(itertools.repeat({'key':'val'}, 7)))
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
['B', 'O', 'B', 'B', 'O', 'B', 'B', 'O', 'B', 'B', 'O', 'B', 'B', 'O', 'B']
['A', 'A', 'A', 'A', 'A']
[[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]]
[{'key': 'val'}, {'key': 'val'}, {'key': 'val'}, {'key': 'val'}, {'key': 'val'}, {'key': 'val'}, {'key': 'val'}]

Other short sequence terminators:

  • accumulate(iterable[,func]) - It returns accumulated sum of numbers if func is not provided else applies binary func to elements of iterable.
  • chain(*iterables) - It loops through all iterables passed as arguments and returns elements of each one by one in sequence they were given input.
  • compress(data,selectors) - It loop through data one by one and returns only that elements for which element with same index in selectors return True.
In [3]:
print(list(itertools.accumulate(range(5,15))))
print(list(itertools.accumulate(range(5,15), lambda x,y : x*y)))
print(list(itertools.accumulate(range(5,15), lambda x,y : y/x)))
print(list(itertools.accumulate('ABCD')))
print(list(itertools.accumulate('ABCD', lambda x,y : [x,y])))

print(list(itertools.chain(range(1,4),range(4, 1,-1),'ABCDE')))

print(list(itertools.compress(range(5,0,-1),[True,False,True,False,True])))
print(list(itertools.compress(range(5,0,-1),[True,None,None,False,True])))
print(list(itertools.compress(range(5,0,-1),[0,1,1,1,0])))
print(list(itertools.compress(range(5,0,-1),[[],[1,2],[],[1,2,3],[]])))
print(list(itertools.compress(range(5,0,-1),[{},{'key':'val'},{'key':'val'},{},{}])))
[5, 11, 18, 26, 35, 45, 56, 68, 81, 95]
[5, 30, 210, 1680, 15120, 151200, 1663200, 19958400, 259459200, 3632428800]
[5, 1.2, 5.833333333333334, 1.3714285714285712, 6.562500000000001, 1.5238095238095235, 7.218750000000002, 1.662337662337662, 7.820312500000002, 1.7902097902097898]
['A', 'AB', 'ABC', 'ABCD']
['A', ['A', 'B'], [['A', 'B'], 'C'], [[['A', 'B'], 'C'], 'D']]
[1, 2, 3, 4, 3, 2, 'A', 'B', 'C', 'D', 'E']
[5, 3, 1]
[5, 1]
[4, 3, 2]
[4, 2]
[4, 3]
  • dropwhile(predicate,iterable) - It drops element as long as predicate condition is True and then it returns all elements.
  • filterfalse(predicate,iterable) - It returns only those elements from iterable for which predicate condition is False.
In [4]:
print(list(itertools.dropwhile(lambda x: x<2, range(1,6))))
print(list(itertools.dropwhile(lambda x: x == 2, range(1,6)))) ## Make a note here that first condition itself is False hence returns all elements
print(list(itertools.dropwhile(lambda x: (x**2) < 5, range(1,6))))
print(list(itertools.dropwhile(lambda x : x in ['A','E','I','O','U'], 'EABCD')))

print(list(itertools.filterfalse(lambda x: x%2==0, range(1,6))))
print(list(itertools.filterfalse(lambda x: x//2 < 2, range(1,6))))
print(list(itertools.filterfalse(None, range(6))))
print(list(itertools.filterfalse(lambda x : x in ['A','E','I','O','U'], 'ABCDE')))
[2, 3, 4, 5]
[1, 2, 3, 4, 5]
[3, 4, 5]
['B', 'C', 'D']
[1, 3, 5]
[4, 5]
[0]
['B', 'C', 'D']
  • groupby(iterable,key=None) - Returns an iterator which consist of key,group pair from iterable based on function provided as key which generates key in pair. If key is not provided then it's set ot identity function(lambda x: x). iterable should be sorted to get proper results/grouping. Elements should be in sorted order to get proper groups.
In [5]:
for key,group in itertools.groupby([2,2,2,3,3,4,4]):
    print(str(key)+ ' : ' + str(list(group)))
for key,group in itertools.groupby(['Arial','Ariel','Bad','Bed','Cat','Catch'],key=lambda x: x[0]):
    print(str(key)+ ' : ' + str(list(group)))

class Employee(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name + ' : , Age : '+str(self.age)

e1 = Employee('Sunny',27)
e2 = Employee('Sumit',27)
e3 = Employee('Anup',35)
e4 = Employee('Ashwin',35)
e5 = Employee('Rohit',38)
e6 = Employee('Irfan',38)
e7 = Employee('Ethesh',22)
e8 = Employee('Kaushal',45)

for key,group in itertools.groupby([e1,e2,e3,e4,e5,e6,e7,e8], key=lambda x: x.age):
    group_desc = [str(item) for item in group]
    print(str(key)+ ' : ' + str(group_desc))

for key,group in itertools.groupby([e1,e2,e3,e4,e5,e6,e7,e8], key=lambda x: x.name[0]):
    group_desc = [str(item) for item in group]
    print(str(key)+ ' : ' + str(group_desc))
2 : [2, 2, 2]
3 : [3, 3]
4 : [4, 4]
A : ['Arial', 'Ariel']
B : ['Bad', 'Bed']
C : ['Cat', 'Catch']
27 : ['Sunny : , Age : 27', 'Sumit : , Age : 27']
35 : ['Anup : , Age : 35', 'Ashwin : , Age : 35']
38 : ['Rohit : , Age : 38', 'Irfan : , Age : 38']
22 : ['Ethesh : , Age : 22']
45 : ['Kaushal : , Age : 45']
S : ['Sunny : , Age : 27', 'Sumit : , Age : 27']
A : ['Anup : , Age : 35', 'Ashwin : , Age : 35']
R : ['Rohit : , Age : 38']
I : ['Irfan : , Age : 38']
E : ['Ethesh : , Age : 22']
K : ['Kaushal : , Age : 45']
  • islice(iterable, stop) - Loops through iterable and returns element from begining till stop index.
  • islice(iterable, start,stop[,step]) - Loops through iterable from start index till stop index using step for item skipping
  • starmap(function,iterable) - executes function using each argouments of iterable as argument to function.
  • takewhile() - It's reverse of dropwhile() function. It returns element until condition is True whereas dropwhile() drops element while condition is True and then returns elements.
In [6]:
print(list(itertools.islice('ABCDE',3)))
print(list(itertools.islice('ABCDE',0,2)))
print(list(itertools.islice('ABCDE',0,None, 3)))

print(list(itertools.starmap(lambda x: x%2, [(2,),(3,),(4,),(5,),(6,),(7,),(8,)])))
print(list(itertools.starmap(lambda x: datetime.fromtimestamp(x), [(6,),(60,),(3600,)])))
print(list(itertools.starmap(lambda x: time.gmtime(x),[(6,),(60,),(3600,)])))

print(list(itertools.takewhile(lambda x: x<2, range(1,6))))
print(list(itertools.takewhile(lambda x: x == 2, range(1,6)))) ## Make a note here that first condition itself is False hence returns no elements
print(list(itertools.takewhile(lambda x: (x**2) < 5, range(1,6))))
print(list(itertools.takewhile(lambda x : x in ['A','E','I','O','U'], 'EABCD')))
['A', 'B', 'C']
['A', 'B']
['A', 'D']
[0, 1, 0, 1, 0, 1, 0]
[datetime.datetime(1970, 1, 1, 0, 0, 6), datetime.datetime(1970, 1, 1, 0, 1), datetime.datetime(1970, 1, 1, 1, 0)]
[time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=6, tm_wday=3, tm_yday=1, tm_isdst=0), time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=1, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0), time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=1, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)]
[1]
[]
[1, 2]
['E', 'A']
  • tee(iterable,n=2) - It returns n independent iterables from single iterable.
  • zip_longest(*iterable, fill_value=None) - It's same as zip() function but returns elements same as longest sequence and fills value specified by fill_value in other small lists.
In [7]:
result = itertools.tee([1,2,3,4], 4)
print([list(item) for item in result ])

result = itertools.tee('ABCDE', 3)
print([list(item) for item in result ])

print(list(itertools.zip_longest([1,2,3,4,5,6],[1,2,4],[1,2,3,4,5])))
print(list(itertools.zip_longest([1,2,3,4,5,6],[1,2,4],[1,2,3,4,5],'NONE')))
print(list(itertools.zip_longest([1,2,3,4,5,6],[1,2,4],[1,2,3,4,5],'NA')))
[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
[['A', 'B', 'C', 'D', 'E'], ['A', 'B', 'C', 'D', 'E'], ['A', 'B', 'C', 'D', 'E']]
[(1, 1, 1), (2, 2, 2), (3, 4, 3), (4, None, 4), (5, None, 5), (6, None, None)]
[(1, 1, 1, 'N'), (2, 2, 2, 'O'), (3, 4, 3, 'N'), (4, None, 4, 'E'), (5, None, 5, None), (6, None, None, None)]
[(1, 1, 1, 'N'), (2, 2, 2, 'A'), (3, 4, 3, None), (4, None, 4, None), (5, None, 5, None), (6, None, None, None)]

Conbinatorics iterators:

  • product(*iterables) - Returns cartesian product of input iterables. To compute product of iterable with itself specify repeat with number of times you want to repeat.
  • permutations(iterable,r=None) - It returns all possible permutations of lenght r of iterable. If r is not specified then all possible permutation of whole iterable is returned.
  • combinations(iterable,r) - Returns all combinations of length r of iterable.
  • combinations_with_replacement(iterable,r) - Returns all combinations of length r of iterable with allowing replacement more than once.
In [8]:
print(list(itertools.product([1,2,3,4],[4,3,2,1])))
print(list(itertools.product([1,2,3,4],[4,3,2,1],[7,8,9])))
print(list(itertools.product([1,2,3,4],[4,3,])))
print(list(itertools.product([1,2,3,4],[4,3,],repeat=2)))
print(list(itertools.product('CBA','ABC')))
print(list(itertools.product([1,2,3,4],repeat=3)))
[(1, 4), (1, 3), (1, 2), (1, 1), (2, 4), (2, 3), (2, 2), (2, 1), (3, 4), (3, 3), (3, 2), (3, 1), (4, 4), (4, 3), (4, 2), (4, 1)]
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 3, 7), (1, 3, 8), (1, 3, 9), (1, 2, 7), (1, 2, 8), (1, 2, 9), (1, 1, 7), (1, 1, 8), (1, 1, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 3, 7), (2, 3, 8), (2, 3, 9), (2, 2, 7), (2, 2, 8), (2, 2, 9), (2, 1, 7), (2, 1, 8), (2, 1, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 3, 7), (3, 3, 8), (3, 3, 9), (3, 2, 7), (3, 2, 8), (3, 2, 9), (3, 1, 7), (3, 1, 8), (3, 1, 9), (4, 4, 7), (4, 4, 8), (4, 4, 9), (4, 3, 7), (4, 3, 8), (4, 3, 9), (4, 2, 7), (4, 2, 8), (4, 2, 9), (4, 1, 7), (4, 1, 8), (4, 1, 9)]
[(1, 4), (1, 3), (2, 4), (2, 3), (3, 4), (3, 3), (4, 4), (4, 3)]
[(1, 4, 1, 4), (1, 4, 1, 3), (1, 4, 2, 4), (1, 4, 2, 3), (1, 4, 3, 4), (1, 4, 3, 3), (1, 4, 4, 4), (1, 4, 4, 3), (1, 3, 1, 4), (1, 3, 1, 3), (1, 3, 2, 4), (1, 3, 2, 3), (1, 3, 3, 4), (1, 3, 3, 3), (1, 3, 4, 4), (1, 3, 4, 3), (2, 4, 1, 4), (2, 4, 1, 3), (2, 4, 2, 4), (2, 4, 2, 3), (2, 4, 3, 4), (2, 4, 3, 3), (2, 4, 4, 4), (2, 4, 4, 3), (2, 3, 1, 4), (2, 3, 1, 3), (2, 3, 2, 4), (2, 3, 2, 3), (2, 3, 3, 4), (2, 3, 3, 3), (2, 3, 4, 4), (2, 3, 4, 3), (3, 4, 1, 4), (3, 4, 1, 3), (3, 4, 2, 4), (3, 4, 2, 3), (3, 4, 3, 4), (3, 4, 3, 3), (3, 4, 4, 4), (3, 4, 4, 3), (3, 3, 1, 4), (3, 3, 1, 3), (3, 3, 2, 4), (3, 3, 2, 3), (3, 3, 3, 4), (3, 3, 3, 3), (3, 3, 4, 4), (3, 3, 4, 3), (4, 4, 1, 4), (4, 4, 1, 3), (4, 4, 2, 4), (4, 4, 2, 3), (4, 4, 3, 4), (4, 4, 3, 3), (4, 4, 4, 4), (4, 4, 4, 3), (4, 3, 1, 4), (4, 3, 1, 3), (4, 3, 2, 4), (4, 3, 2, 3), (4, 3, 3, 4), (4, 3, 3, 3), (4, 3, 4, 4), (4, 3, 4, 3)]
[('C', 'A'), ('C', 'B'), ('C', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('A', 'A'), ('A', 'B'), ('A', 'C')]
[(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 3, 1), (1, 3, 2), (1, 3, 3), (1, 3, 4), (1, 4, 1), (1, 4, 2), (1, 4, 3), (1, 4, 4), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 1, 4), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 3, 1), (2, 3, 2), (2, 3, 3), (2, 3, 4), (2, 4, 1), (2, 4, 2), (2, 4, 3), (2, 4, 4), (3, 1, 1), (3, 1, 2), (3, 1, 3), (3, 1, 4), (3, 2, 1), (3, 2, 2), (3, 2, 3), (3, 2, 4), (3, 3, 1), (3, 3, 2), (3, 3, 3), (3, 3, 4), (3, 4, 1), (3, 4, 2), (3, 4, 3), (3, 4, 4), (4, 1, 1), (4, 1, 2), (4, 1, 3), (4, 1, 4), (4, 2, 1), (4, 2, 2), (4, 2, 3), (4, 2, 4), (4, 3, 1), (4, 3, 2), (4, 3, 3), (4, 3, 4), (4, 4, 1), (4, 4, 2), (4, 4, 3), (4, 4, 4)]
In [9]:
print(list(itertools.permutations('ABCDE', r=2))) ## Order of elements does matter in permutations
print(list(itertools.permutations('ABC')))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'A'), ('B', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'A'), ('C', 'B'), ('C', 'D'), ('C', 'E'), ('D', 'A'), ('D', 'B'), ('D', 'C'), ('D', 'E'), ('E', 'A'), ('E', 'B'), ('E', 'C'), ('E', 'D')]
[('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]
In [10]:
print(list(itertools.combinations('ABCDE', r=2))) ## Order of elements does not matter in combintations
print(list(itertools.combinations_with_replacement('ABCDE', r=2))) ## Make a note that element was replaced hence there are extra entry of element with itself.
print(list(itertools.combinations('ABC', r=3)))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'D'), ('C', 'E'), ('D', 'E')]
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'C'), ('C', 'D'), ('C', 'E'), ('D', 'D'), ('D', 'E'), ('E', 'E')]
[('A', 'B', 'C')]

Let other learners know about this article @ Google LinkedIn Facebook
Sunny Solanki  Sunny Solanki