Search code examples
pythonrandompython-itertools

Random and Itertools


I have some sample code that iterates through two different ranges of numbers successfully, but I want to add functionality to it so that it moves through the chained ranges randomly like so:

import itertools
import random

for f in random.sample(itertools.chain(range(30, 54), range(1, 24)), 48):

    print f

However this produces the following error:

Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    for f in random.sample(itertools.chain(range(30, 54), range(1, 24)), 48):
  File "G:\Python27\lib\random.py", line 321, in sample
    n = len(population)
TypeError: object of type 'itertools.chain' has no len()

Can anyone advise the amendments needed to make this function as intended?


Solution

  • A quick fix would be as follows:

    for f in random.sample(list(itertools.chain(range(30, 54), range(1, 24))), 48):
    

    The problem with your code is that to sample from some iterable randomly, you need to know its length first, but itertools.chain is an iterable that provides only the __iter__ method and no __len__.

    Basically, to do random.choice or random.sample or anything that involves choosing elements at random, you'll need a sequence or a set, which means that sequence should be finite. Iterables that don't provide the __len__ method are considered infinite as you'll never know how many elements will be produced until the iterable's exhausted, if at all.