iterating over a list as if it were a circular list

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Mar 8 12:59:42 EST 2013


On Thu, 07 Mar 2013 09:27:42 +0000, Sven wrote:

> Additionally, what if I wanted to pull a random element from N, but I
> want to ensure all elements from N have been used before starting to
> pick already chosen random elements again. So far I thought of
> duplicating the list and removing the randomly chosen elements from the
> list, and when it's empty, re-copying it. But that seems a little
> "wrong" if you know what I mean.

An infinite generator is probably the best solution:

import random
def sample_without_replacement(alist):
    blist = alist[:]  # Copy the list.
    while True:
        random.shuffle(blist)
        for value in blist:
            yield value


Notice that I make a copy of the list before shuffling. That avoids side-
effects where calling sample_without_replacement on a list modifies it.

To use it, you do something like this:

it = sample_without_replacement([1, 2, 3, 4, 5, 6])
next(it)
=> prints a random value
next(it)
=> and a second random value

To grab twenty random values all at once, you can either do this:

it = sample_without_replacement([1, 2, 3, 4, 5, 6])
values = [next(it) for i in range(20)]


or this:

import itertools
it = sample_without_replacement([1, 2, 3, 4, 5, 6])
values = itertools.islice(it, 20)



-- 
Steven



More information about the Python-list mailing list