从迭代器中排除第一个元素(Python)

时间:2018-07-19 19:16:06

标签: python python-3.x iterator

我有一个生成器函数A

例如(实际上我有一个更复杂的功能A

def A():
    yield from [i**2 for i in range(20)]

编写另一个生成器函数B,我想枚举A返回的所有元素,除了第一个元素。

在Python 3中实现此功能的简洁方法是什么?

3 个答案:

答案 0 :(得分:7)

使用itertools.islice

itertools.islice(generator,1,None)

答案 1 :(得分:3)

通常,您不需要在表达式中使用它,因此只需调用next(it),而忽略结果即可消耗和丢弃第一个元素。


但是,如果迭代器可能为空,则必须决定要发生的事情:

  • 也许您想加注StopIteration,在这种情况下,next(it)很好。
  • 也许您想提出其他建议,在这种情况下,您next(it)except StopIteration: raise SomethingElse()内。
  • 也许您只是想让迭代器为空,在这种情况下,您可以调用next(it, None)

您可以在stdlib和docs中找到这些示例。例如,如果您浏览itertools中的食谱:

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

这正是您想要做的—跳过b的第一个元素。而且,如果iterable为空,则您不想在这里出现错误;您只想不进行任何迭代。因此,next(b, None)


如果需要在表达式中间执行此操作怎么办?

然后,您可以编写一个跳过第一个元素的函数:

def skip_first(iterable):
    it = iter(iterable)
    next(it, None)
    return it

(同样,对于空的可迭代对象,您必须决定要发生什么。)

这将返回迭代器的第一个跳过版本,因此您可以内联使用它。 (当然,它会突变您传入的迭代器,但是通常只使用不保留任何引用的临时值,所以这不是问题。)

或者,如果您需要返回一个生成器而不是一个任意的迭代器(通常不需要):

def skip_first(iterable):
    it = iter(iterable)
    next(it, None)
    yield from it

或者您可以使用同一想法的更通用版本itertools.islice。以下具有相同的效果:

it = skip_first(it)
it = itertools.islice(it, 1, None)

虽然我们使用itertools食谱,但值得一看的是consume

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is None, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

忘记None部分;有趣的是,它跳过了nislice的{​​{1}}元素。 (请注意,它是在原位更改next,而不返回任何内容。)

答案 2 :(得分:1)

免责声明:请参阅上面的@abarnert和@Solaxun的答案。

只是认为应该提到以下内容

如果有original = iter((1,2,3,4,5))

然后

first, remaining = next(original), original

其中remaining是没有第一个元素的迭代器。