Search code examples
pythonlistrandomgeneratorshuffle

How to use random.shuffle() on a generator? python


How do I use random.shuffle() on a generator without initializing a list from the generator? Is that even possible? if not, how else should I use random.shuffle() on my list?

>>> import random
>>> random.seed(2)
>>> x = [1,2,3,4,5,6,7,8,9]
>>> def yielding(ls):
...     for i in ls:
...             yield i
... 
>>> for i in random.shuffle(yielding(x)):
...     print i
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/random.py", line 287, in shuffle
    for i in reversed(xrange(1, len(x))):
TypeError: object of type 'generator' has no len()

Note: random.seed() was designed such that it returns the same output after each script run?


Solution

  • In order to shuffle the sequence uniformly, random.shuffle() needs to know how long the input is. A generator cannot provide this; you have to materialize it into a list:

    lst = list(yielding(x))
    random.shuffle(lst)
    for i in lst:
        print i
    

    You could, instead, use sorted() with random.random() as the key:

    for i in sorted(yielding(x), key=lambda k: random.random()):
        print(i)
    

    but since this also produces a list, there is little point in going this route.

    Demo:

    >>> import random
    >>> x = [1,2,3,4,5,6,7,8,9]
    >>> sorted(iter(x), key=lambda k: random.random())
    [9, 7, 3, 2, 5, 4, 6, 1, 8]