Iterator Functions in Python (itertools) | Creating iterators for efficient looping

Iterator functions in Python help in iterating or looping through a sequence efficiently. Some of the useful iterator functions in Python are accumulate(), chain(), chain.from_iterable(), compress(), dropwhile(), filterfalse(), islice(), starmap(), takewhile(), tee() and zip_longest(). These functions are called itertools as they are available inside the module named itertools. So whenever you plan on using these functions in your program, ensure to import the itertools module. When compared to the formal iterator() function, these inbuilt functions are easy to implement in a single line of code. Let’s now look at how these iterator functions in Python can be used or implemented while programming.

a) accumulate (seq, func)

The accumulate() iteration function is used to perform operations such as arithmetic, relational etc on the elements of a sequence successively. This function takes two arguments, the input sequence (seq) and the operation or function that has to be performed on the input sequence (func). Refer standard operator functions to know the available inbuilt functions. If in case, no operation or function is specified as an input, then addition operation takes place by default. Also, to output the elements of the sequence, you can use the method list() or the method tuple(). Let’s now see how this works.
#adding successive elements of a list
from itertools import *
from operator import *
list1 = [4, 6, 2, 9]
print (list(accumulate(list1)))

#performing successive multiplication
print (list(accumulate(list1, mul)))

#performing successive division
print (list(accumulate(list1, truediv)))

#adding successive elements of a tuple
from itertools import *
tuple1 = (4, 6, 2, 9)
print (tuple(accumulate(tuple1)))
[4, 10, 12, 21]
[4, 24, 48, 432]
[4, 0.6666666666666666, 0.3333333333333333, 0.037037037037037035]
(4, 10, 12, 21) 

Explanation: Here, as you can observe, we have performed several operations on the list using inbuilt functions arithemtic functions like mul, truediv etc. 

iterator functions in Python

b) chain (seq1, seq2….)

This function is used to print all the elements of the given input sequence. If multiple sequences are used, then this function first returns all the elements of the first sequence until it is exhausted and then proceeds to the next sequence. For instance, 

#printing a sequence
from itertools import *
tuple1 = (4, 6, 2, 9)
print (tuple(chain(tuple1)))

#printing multiple sequences
tuple2 = (3, 8, 7, 5)
print (tuple(chain(tuple1, tuple2)))

#printing multiple sequences
print (list(chain([1, 2, 9, 7, 6], [4, 6, 2, 9, 0])))
print (tuple(chain((1, 2, 9, 7, 6), (4, 6, 2, 9, 0))))

#printing multiple sequences
print (tuple(chain(('FACE', 'PREP'))))
print (tuple(chain('FACE', 'PREP')))
(4, 6, 2, 9)
(4, 6, 2, 9, 3, 8, 7, 5)
[1, 2, 9, 7, 6, 4, 6, 2, 9, 0]
(1, 2, 9, 7, 6, 4, 6, 2, 9, 0)
('FACE', 'PREP')
('F', 'A', 'C', 'E', 'P', 'R', 'E', 'P')

c) chain.from_iterable (seq)

This function works the same as that of the chain() function, but the argument here is a list of lists or any other iterable container. For example,

from itertools import *
list1 = [[4, 6, 2, 9]]
print (list(chain.from_iterable(list1)))

#alternate way
print (list(chain.from_iterable([[1, 2, 6, 9]])))
[4, 6, 2, 9]
[1, 2, 6, 9]

d) compress (seq, selector)

The compress () function selectively picks the values to be returned (printed) from the given input sequence based on boolean values in a list which is passed as another argument. The arguments corresponding to the boolean value True are printed and the remaining are skipped. This function stops when either the input sequence or the boolean list exhausts.

Let us consider this example,

from itertools import *
print (list(compress("FACE", [1, 0, 1, 0])))
Output: ['F', 'C']

Explanation: In the given list of boolean values, the values are True at the indexes 0 and 2. Hence, the characters in the given string at the indexes 0 and 2 are printed.

Similarly, consider this example,

from itertools import *
print (list(compress([5, 2, 6, 9], [1, 0, 1, 0])))
Output: [5, 6]

e) dropwhile (func, seq)

This iterator starts printing or returning the elements of the given input sequence only after the function returns False for the first time. For instance,

#program to return non-multiples of 5
from itertools import *
list1 = [5, 15, 7, 9, 10]
print (list(dropwhile(lambda num: num % 5 == 0, list1)))
[7, 9, 10]
Explanation: For the first time, the value 5 is passed to the variable ‘num’ of the function. The condition 5 % 5 == 0 is True. For the second time the condition is True. For the third time, the condition is False. Hence, this function starts printing the elements from the third position.

f) filterfalse (func, seq)

This function prints only the values that return false for the passed function. Let us consider the below example for better understanding.
#program to return non-multiples of 5
from itertools import *
list1 = [5, 15, 7, 9, 10]
print (list(filterfalse(lambda num : num % 5 == 0, list1)))
[7, 9]

g) islice (iterable, start, stop, step)

The islice() iterator returns selective items from an iterable. This iterator takes 4 arguments, iterable container, start index, stop index and step. If the start index is a non-zero value, then all the elements in the iterable before that particular index will be skipped. Once it reaches the start index, elements are returned consecutively unless the step is set higher than one. Also, if the stop is given as None, then the iteration continues until the elements get exhausted.

Note: Unlike the regular slicing, islice() does not support negative index values.

#program using islice itertool
from itertools import*
List1 = [2, 4, 9, 1, 3, 7, 17, 15, 18]
print ("The sliced list values are : ",end="")

#when step is 2
print (list(islice(List1, 1, 6, 2)))

#when start is set as None
print (list(islice(List1, None , 6, 2)))

#when stop is set as None
print (list(islice(List1, 1, None, 2)))

#when boh start & stop are set as None
print (list(islice(List1, None, None, 2)))
The sliced list values are : [4, 1, 7]
[2, 9, 3]
[4, 1, 7, 15]
[2, 9, 3, 17, 18]

h) starmap (func., tuple list) 

The starmap () iterator function takes a function and tuple list as arguments and returns the value obtained by computing the function using the elements of the tuple list. For example,

#program using starmap
from itertools import*

#declaring a tuple list
List1 = [(2, 7, 8, 1, 0, 6)]

print ("The values acc. to function are : ",end="")
print (list(starmap(min, List1))) #Here min is a function which returns the minimum of the given values
The values acc. to function are : [0]

i) tee (iterator, count)

The tee() iterator function returns independent iterators from a single iterator. The number of independent iterators returned is equal to the value of count inputted.

#program using tee()
from itertools import*

#declaring a list
List1 = [2, 9, 6, 3, 0, 2]

#storing the list as an iterator
iterator = iter(List1)

#making 3 iterators
it = tee(iterator, 3)

#looping to print the iterators
print ("The iterators are : ") 
for i in range (0,3): 
print (list(it[i]))
The iterators are :
[2, 9, 6, 3, 0, 2]
[2, 9, 6, 3, 0, 2]
[2, 9, 6, 3, 0, 2]

j) takewhile (func, iterable) 

The takewhile() iterator is opposite of dropwhile(). It prints the elements of the iterable till the function returns false for the very first time. Have a look at the below example. The same example outputs [7, 9, 10] when dropwhile is used.
#program to return non-multiples of 5
from itertools import *
list1 = [5, 15, 7, 9, 10]
print (list(takewhile(lambda num: num % 5 == 0, list1)))
[5, 15]

k) zip_longest (iterable1, iterable2, fillval) 

You can input any number of iterables in this function. Let us assume you have inputted two iterables, iterable1 & iterable2. This iterator prints the values of iterable1 and iterable 2 alternatively in a sequence. If one of the iterables is exhausted, the remaining values are filled with the value assigned to fillval.

#program using zip_longest()
from itertools import*
print (*(zip_longest('FACE Prep','Python',fillvalue='_' )))
print (*(zip_longest([1, 2, 3, 4],[5, 6, 7, 8, 9],fillvalue='_' )))
('F', 'P') ('A', 'y') ('C', 't') ('E', 'h') (' ', 'o') ('P', 'n') ('r', '_') ('e', '_') ('p', '_')
(1, 5) (2, 6) (3, 7) (4, 8) ('_', 9)

Also, here are some useful generator iterators & infinite iterators that perform various operations.

Iterator & SyntaxDescription
product (iter1, iter2…………..)This iterator returns the cartesian product of the iterables passed as arguments.
permutations (iter, r)This iterator returns successive r length permutations of elements in the iterable.
combinations (iterable, r)This iterator returns r length subsequences of elements from the input iterable in sorted order. Elements are treated as unique based on their position, not on their value. So if the input elements are unique, there will be no repeat values in each combination.
combinations_with_replacement (iterable, r)This iterator returns r length subsequences of elements from the input iterable allowing individual elements to be repeated more than once.
count (start, step)This iterator returns the values starting from the start number and prints infinitely. If step is mentioned, the numbers are skipped accordingly, else step is 1 by default.
cycle (iterable)This iterator returns all the values in the iterable. It restarts printing from the beginning if the iterable is exhausted. This way, it goes on infinitely.
repeat (object, times)This iterator returns the object over and over again based on the times value.