由于生成器懒惰地返回值,如何确定从生成器返回的值是否是一个但是最后一个?我在这上面花了一个小时就搞定了。
任何帮助表示赞赏。它甚至可能吗?
谢谢,Boda Cydo!
答案 0 :(得分:10)
您可以将生成器包装在生成器中,该生成器生成一对对,其第一个元素是布尔值,告诉您元素是否是最后一个:
def ending(generator):
z2 = generator.next()
z1 = generator.next()
for x in generator:
yield (False, z2)
z2, z1 = z1, x
yield (True, z2)
yield (False, z1)
让我们在一个简单的迭代器上测试它:
>>> g = iter('abcd')
>>> g
<iterator object at 0x9925b0>
你应该得到:
>>> for is_last_but_one, char in ending(g):
... if is_last_but_one:
... print "The last but one is", char
...
The last but one is c
看看幕后发生了什么:
>>> g = iter('abcd')
>>> for x in ending(g):
... print x
...
(False, 'a')
(False, 'b')
(True, 'c')
(False, 'd')
答案 1 :(得分:2)
如果你想在不消耗它的情况下看到迭代器的任意未来值,你可以将迭代器包装在一个'peekable'迭代器中,它可以缓冲未来的值。
import collections
class PeekIter(object):
def __init__(self, iterable):
self._iter = iter(iterable)
self._peekbuf = collections.deque()
def next(self):
if self._peekbuf:
return self._peekbuf.popleft()
else:
return self._iter.next()
def peek(self, future=0, default=None):
try:
while len(self._peekbuf) <= future:
self._peekbuf.append(self._iter.next())
return self._peekbuf[future]
except StopIteration:
return default
然后,您可以在不消耗它们的情况下查看未来的值。
>>> p = PeekIter(range(3))
>>> p.peek()
0
>>> p.next()
0
>>> p.peek(0)
1
>>> p.peek(0)
1
>>> p.peek(1)
2
>>> p.peek(2)
>>> sentinel = object()
>>> sentinel
<object object at 0x28470>
>>> p.peek(1, sentinel)
2
>>> p.peek(2, sentinel)
<object object at 0x28470>
答案 2 :(得分:1)
基于itertools的解决方案
from itertools import tee, islice, repeat, chain, izip
def gen_with_offset(gen, offset):
gen1, gen2 = tee(gen)
gen2 = (False for x in gen2)
gen2 = chain(islice(gen2, offset, None), [True], repeat(False))
for g, sentinel in izip(gen1, gen2):
yield g, sentinel
Usage:
>>> gex = iter('abcedefg')
>>> for p in gen_with_offset(gex, 4):
... print p
...
('a', False)
('b', False)
('c', False)
('e', False)
('d', True)
('e', False)
('f', False)
('g', False)
>>>