获取python的itertools循环当前元素

问题描述 投票:0回答:3

我知道您可以使用

c = cycle(['a', 'b', 'c'])
使用
c.next()
在元素之间循环,但是有没有办法获取迭代器的当前元素?

例如,如果

c.next()
返回
'c'
,则意味着迭代器之前位于
'b'
。有没有一种方法可以在不使用
'b'
的情况下获得
next()

python python-2.7
3个回答
5
投票

迭代器/生成器没有任何方法来获取当前值。您应该保留对它的引用,或者创建一些为您保留它的包装器。


2
投票

注意:这仅在没有重复元素的情况下有效。 这是否是一个严重的实际限制取决于每个人的使用情况。 就我而言,我合作过的大多数

itertools.cycle
都属于这一类。

实际上可以通过辅助函数获取

cycle
的当前状态以及其他信息。 它实际上使用
next
,但这对调用者来说是透明的。

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))

产生以下输出

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]

实际上可以利用该功能来“倒带”一个周期

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

尝试

shift_cycle(c, -2)
print('cycle state =', get_cycle_state(c))

0
投票

这是一个简单的包装:

from itertools import cycle
from typing import Generic, Iterator, TypeVar


_T = TypeVar("_T")


class Cycler(Generic[_T]):
    def __init__(self, cycle: "cycle[_T]") -> None:
        self._cycle = cycle

    @property
    def current(self):
        if not hasattr(self, "_current"):
            return next(self)
        return self._current

    def __iter__(self) -> Iterator[_T]:
        return self

    def __next__(self):
        self._current = next(self._cycle)
        return self._current

这个演示—

letters = ("a", "b", "c")
letters_cycler = Cycler(cycle(letters))

# The cycle can start by attempting to get the current element, or by calling next on it
print("Start cycle")
# print(next(letters_cycler))
print("Check:", letters_cycler.current)
print()

print("Next: ", next(letters_cycler))
print("Check:", letters_cycler.current)
print()

print("Next: ", next(letters_cycler))
print("Check:", letters_cycler.current)
print()

print("Next: ", next(letters_cycler))
print("Check:", letters_cycler.current)
print()

print("Next: ", next(letters_cycler))
print("Check:", letters_cycler.current)
print()

—打印:

Start cycle
Check: a

Next:  b
Check: b

Next:  c
Check: c

Next:  a
Check: a

Next:  b
Check: b

这个演示—

letters_cycler_new = Cycler(cycle(letters))
for i, letter in enumerate(letters_cycler_new):
    print(letter)
    assert letter == letters_cycler_new.current
    if i == 6:
        break

—打印:

a
b
c
a
b
c
a
© www.soinside.com 2019 - 2024. All rights reserved.