How to merge multiple iterators to get a new iterator which will iterate over them randomly?

Viewed 326

Suppose I have a list of iterators:

iterators = [ iter([2, 3, 4]), iter([7, 9]), iter([-1, -2, -3, -4]) ]

How can I create a new iterator using the above iterators such that at each step it will randomly select one of the iterators present in the list (which are not yet finished) and output the next element from that? It should keep outputting elements until all the iterators have finished.

So, for example, if the new iterator is it_combined, I may get the following output when trying to iterate on it

>>> for it in it_combined:
...     print(it, end=" ")
...
2 7 3 -1 4 -2 -3 -4 9
2 Answers

You can use random.choice to randomly select an iterator from a list. You then have to make sure to delete this iterator from the list once you've exhausted it.

You can use a generator to implement the merging / sampling of your iterators:

import random

random.seed(42)


def combine_iterators(iterators):
    while iterators:
        it = random.choice(iterators)
        try:
            yield next(it)
        except StopIteration:
            iterators.remove(it)


merged_iterator = combine_iterators(
    [iter([2, 3, 4]), iter([7, 9]), iter([-1, -2, -3, -4])]
)
for x in merged_iterator:
    print(x, end=" ")

Outputs:

-1 2 3 -2 7 4 9 -3 -4

Does this fit your needs?

Select a random iterator and print one of its values. Once that iterator throws its exception, remove it from the list. Continue until all iterators are gone.

import random
iterators = [ iter([2, 3, 4]), iter([7, 9]), iter([-1, -2, -3, -4]) ]

while len(iterators) > 0:
    which = random.randint(0, len(iterators)-1)
    it = iterators[which]
    try:
        print(next(it))
    except Exception:
        del iterators[which]
Related