如果未使用特定迭代器,则类似 zip 的函数将失败

如果最右边的迭代器没有被消耗,我想要一个类似 zip 的函数。它应该屈服直到失败。


例如


>>> a = ['a', 'b', 'c']

>>> b = [1, 2, 3, 4]


>>> myzip(a, b)

Traceback (most recent call last):

    ...

ValueError: rightmost iterable was not consumed


>>> list(myzip(b, a))

[(1, 'a'), (2, 'b'), (3, 'c')]

也许标准库中有一个函数可以帮助解决这个问题?


重要的提示:


在真实的上下文中,迭代器不是在对象上,所以我不能只检查长度或索引它们。


编辑:


这是我到目前为止想出的


def myzip(*iterables):

    iters = [iter(i) for i in iterables]


    zipped = zip(*iters)


    try:

        next(iters[-1])

        raise ValueError('rightmost iterable was not consumed')

    except StopIteration:

        return zipped

这是最好的解决方案吗?它不会保持迭代器的状态,因为我调用了它的 next,这可能是一个问题。


浮云间
浏览 138回答 3
3回答

慕的地6264312

有几种不同的方法可以做到这一点。您可以将法线zip()与迭代器一起使用并手动检查它是否已耗尽。def check_consumed(it):    try:        next(it)    except StopIteration:        pass    else:        raise ValueError('rightmost iterable was not consumed')b_it = iter(b)list(zip(a, b_it))check_consumed(b_it)您可以将法线包裹起来zip()为您进行检查。def myzip(a, b):    b_it = iter(b)    yield from zip(a, b_it)    # Or, if you're on a Python version that doesn't have yield from:    #for item in zip(a, b_it):    #    yield item    check_consumed(b_it)list(myzip(a, b))您可以zip()使用iter()和从头开始编写自己的代码next()。(这个没有代码,因为选项 2 在各方面都优于这个)

GCT1015

使用 itertools 中的 zip_longest 的其他选项。如果所有列表都被消耗,它也会返回 true 或 false。也许不是最有效的方法,但可以改进:from itertools import zip_longesta = ['a', 'b', 'c', 'd']b = [1, 2, 3, 4, 5]c = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff']def myzip(*iterables):    consumed = True    zips = []    for zipped in zip_longest(*iterables):      if None in zipped:        consumed = False       else:        zips.append(zipped)    return [zips, consumed]list(myzip(a, b, c))#=> [[('a', 1, 'aa'), ('b', 2, 'bb'), ('c', 3, 'cc'), ('d', 4, 'dd')], False]
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python