Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting python's itertools cycle current element

I know you can use c = cycle(['a', 'b', 'c']) to cycle between the elements using c.next(), but is there away to get the iterator's current element?

for example if c.next() returned 'c', it means that iterator was at 'b' before. Is there a way I can get 'b' without using next()?

like image 798
Algorithmatic Avatar asked Jul 03 '16 06:07

Algorithmatic


People also ask

What does Itertools cycle do in Python?

This module implements a number of iterator building blocks inspired by constructs from APL, Haskell, and SML. Each has been recast in a form suitable for Python.

What is Islice in Python?

islice() functionThis iterator selectively prints the values mentioned in its iterable container passed as an argument. Syntax: islice(iterable, start, stop, step)

Is Itertools faster than for loops?

While this is a perfectly fine approach, it is important to remember that utilizing the itertools iterators means using iterators that are Pythonic implementations of iterators elsewhere. That being said, the iterators from itertools are often significantly faster than regular iteration from a standard Python for loop.

What is chain in Python?

chain() function It is a function that takes a series of iterables and returns one iterable. It groups all the iterables together and produces a single iterable as output.


2 Answers

Iterators/generators don't have any way to get the current value. You should either keep a reference to it or create some wrapper that holds onto it for you.

like image 97
cs95 Avatar answered Oct 21 '22 12:10

cs95


Note: This only works if there are no repeated elements. Whether this is a serious practical limitation depends on each one's use. In my case, most of the itertools.cycle I have worked with fall under this category.

One can actually get the current state of a cycle with a helper function, and other info as well. It actually uses next, but this is transparent to the caller.

import itertools 

def get_cycle_props(cycle) :
    """Get the properties (elements, length, current state) of a cycle, without advancing it"""
    # Get the current state
    partial = []
    n = 0
    g = next(cycle)
    while ( g not in partial ) :
        partial.append(g)
        g = next(cycle)
        n += 1
    # Cycle until the "current" (now previous) state
    for i in range(n-1) :
        g = next(cycle)
    return (partial, n, partial[0])

def get_cycle_list(cycle) :
    """Get the elements of a cycle, without advancing it"""
    return get_cycle_props(cycle)[0]

def get_cycle_state(cycle) :
    """Get the current state of a cycle, without advancing it"""
    return get_cycle_props(cycle)[2]

def get_cycle_len(cycle) :
    """Get the length of a cycle, without advancing it"""
    return get_cycle_props(cycle)[1]

# initialize list 
test_list = [3, 4, 5, 7, 1] 
c = itertools.cycle(test_list)
print('cycle state =', get_cycle_state(c))
print('cycle length =', get_cycle_len(c))
print('cycle list =', get_cycle_list(c))
next(c)
print('cycle state =', get_cycle_state(c))
print('cycle length =', get_cycle_len(c))
print('cycle list =', get_cycle_list(c))

produces the following output

cycle state = 3
cycle length = 5
cycle list = [3, 4, 5, 7, 1]
cycle state = 4
cycle length = 5
cycle list = [4, 5, 7, 1, 3]

This can actually be taken advantage of to "rewind" a cycle, with the function

def shift_cycle(cycle, npos=0) :
    """Shift a cycle, a given number of positions (can be negative)."""
    (cycle_list, nelem, curr_state) = get_cycle_props(cycle)
    for i in range(nelem+npos) :
        g = next(cycle)
    return

Try

shift_cycle(c, -2)
print('cycle state =', get_cycle_state(c))
like image 28
sancho.s ReinstateMonicaCellio Avatar answered Oct 21 '22 12:10

sancho.s ReinstateMonicaCellio