在Python中为字符串实现lookahead迭代器

Sco*_*ott 7 python algorithm

我正在做一些需要一个前瞻标记的解析.我想要的是一个快速函数(或类?),它将采用迭代器并将其转换为表单中的元组列表(token,lookahead),这样:

>>> a = ['a', 'b', 'c', 'd']
>>> list(lookahead(a))
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', None)]
Run Code Online (Sandbox Code Playgroud)

基本上,这对于在这样的迭代器中展望是很方便的:

for (token, lookahead_1) in lookahead(a):
  pass
Run Code Online (Sandbox Code Playgroud)

虽然,我不确定在itertools中是否有这个技术或功能的名称已经会这样做.有任何想法吗?

谢谢!

Joh*_*ooy 11

如果你只是使用列表,有更简单的方法 - 请参阅Sven的回答.这是为一般迭代器执行此操作的一种方法

>>> from itertools import tee, izip_longest
>>> a = ['a', 'b', 'c', 'd']
>>> it1, it2 = tee(iter(a))
>>> next(it2)  # discard this first value
'a'
>>> [(x,y) for x,y in izip_longest(it1, it2)]
    # or just list(izip_longest(it1, it2))
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', None)]
Run Code Online (Sandbox Code Playgroud)

以下是如何在问题循环中使用它.

>>> it1,it2 = tee(iter(a))
>>> next(it2)
'a'
>>> for (token, lookahead_1) in izip_longest(it1,it2):
...     print token, lookahead_1
... 
a b
b c
c d
d None
Run Code Online (Sandbox Code Playgroud)

最后,这是您正在寻找的功能

>>> def lookahead(it):
...     it1, it2 = tee(iter(it))
...     next(it2)
...     return izip_longest(it1, it2)
... 
>>> for (token, lookahead_1) in lookahead(a):
...     print token, lookahead_1
... 
a b
b c
c d
d None
Run Code Online (Sandbox Code Playgroud)


sen*_*rle 8

我喜欢Svengnibbler的答案,但出于某种原因,我喜欢滚动自己的发电机.

def lookahead(iterable, null_item=None):
    iterator = iter(iterable) # in case a list is passed
    prev = iterator.next()
    for item in iterator:
        yield prev, item
        prev = item
    yield prev, null_item
Run Code Online (Sandbox Code Playgroud)

测试:

>>> for i in lookahead(x for x in []):
...     print i
... 
>>> for i in lookahead(x for x in [0]):
...     print i
... 
(0, None)
>>> for i in lookahead(x for x in [0, 1, 2]):
...     print i
... 
(0, 1)
(1, 2)
(2, None)
Run Code Online (Sandbox Code Playgroud)

编辑:Karl和ninjagecko提出了一个很好的观点 - 传入的序列可能包含None,因此使用None最终的前瞻值可能会导致歧义.但是没有明显的选择; 在许多情况下,模块级常量可能是最好的方法,但对于像这样的一次性函数可能有点过分 - 更不用说bool(object()) == True可能导致意外行为的事实.相反,我添加了null_item一个默认值为的参数None- 这样用户可以传递任何对他们需要有意义的东西,无论是简单的object()哨兵,自己创造的常量,还是具有特殊行为的类实例.由于大部分时间None都是明显的,甚至可能是预期的行为,因此我将其None作为默认行为.


Sve*_*ach 6

通常的方法是为列表执行此a操作

from itertools import izip_longest
for token, lookahead in izip_longest(a, a[1:]):
    pass
Run Code Online (Sandbox Code Playgroud)

对于最后一个令牌,您将获得None前瞻性令牌.

如果要避免引入列表的副本a[1:],可以islice(a, 1, None)改为使用.对于任意迭代的略微修改,请参阅gnibbler答案.对于一个简单易用的生成器函数也适用于任意迭代,请参阅senderle的答案.

  • OP询问在迭代器上执行此操作,但这假设一个列表. (2认同)