Search code examples
pythonpython-itertools

python itertools: Using cycle with islice


Question:

I have the code below. I want to know why does it not matter whether or not I include the line with the comment in the code below.

#!/usr/bin/env python

from itertools import *
import time
cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] )
p = 3
while p:
    try:
        for k in cc:
            print k.next()
    except StopIteration:
        p = p - 1
        cc = cycle(islice(cc,  p))  # this does not matter

Output:

1
4
5
2
6
3

Also checkout roundrobin recipe at

http://docs.python.org/2.7/library/itertools.html

This code shows that islice is impacting cc

#!/usr/bin/env python

from itertools import *
import time
cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] )
p = 3
while p:
    try:
        for k in cc:
            print k,k.next()
    except StopIteration:
            print "stop iter"
            p = p - 1
            cc = cycle(islice(cc,  p)) 

Output

<listiterator object at 0x7f32bc50cfd0> 1
<listiterator object at 0x7f32bc518050> 4
<listiterator object at 0x7f32bc518090> 5
<listiterator object at 0x7f32bc50cfd0> 2
<listiterator object at 0x7f32bc518050> stop iter
<listiterator object at 0x7f32bc518090> 6
<listiterator object at 0x7f32bc50cfd0> 3
<listiterator object at 0x7f32bc518090> stop iter
<listiterator object at 0x7f32bc50cfd0> stop iter

Solution

  • well... it looks like it's doing what is expected here.

    So, normally, cycle works like this:

    cycle([1,2,3,4,5]) -> [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
    

    It's going to store off values until it gets a StopIterator, and then it's going to start returning values from its saved list. In this case, that's going to be [iter(a), iter(b), iter(c)] (where iter(x) is a listiterator object itself, across whatever is inside). So chain is actually returning something like this:

    [iter(a), iter(b), iter(c), iter(a), iter(b), iter(c), iter(a), iter(b), iter(c), ...]
    

    What looks looks like when you run it:

    [1, 4, 5, 2, StopIterator]
    

    But that's the value of k.next(), not k. the cc itself is not returning the StopIterator, the object it returns is.

    Now, you call islice(cc,2). This should return the sequence [iter(c), iter(a)], as those are the next two items in the sequence. Again, you want cc to cycle them, but now you should get

    [iter(c), iter(a), iter(c), iter(a), iter(c), iter(a), ...]
    

    You won't notice much of a difference yet, but that's because your slice is less than the length of the original. In other words, the original would have gone [iter(c), iter(a), iter(b), iter(c), iter(a), ...]

    but you have to go farther than two items to see that difference, and...

    You start pulling items off and you get

    [6, 3, StopIterator]
    

    Only two items, so they are the same two items you'd get without the islice.

    Now, when you do the islice(cc, 2), you get the next two items which are [iter(a), iter(c)]. Both of these are exhausted, so you get

    [StopIterator]
    

    and your exact sequence.

    I don't know what you are expecting, but this works exactly as i would expect it to.