没有填充值的 zip_longest [英] zip_longest without fillvalue

查看:23
本文介绍了没有填充值的 zip_longest的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找 Python 的 zipzip_longest 函数(来自 itertools 模块)之间的中间地带,它耗尽了所有给定的迭代器,但不填写任何内容.因此,例如,它应该像这样转置元组:

I am searching for a middle ground between Python's zip and zip_longest functions (from the itertools module), that exhausts all given iterators, but does not fill in anything. So, for example, it should transpose tuples like so:

(11, 12, 13    ),        (11, 21, 31, 41),
(21, 22, 23, 24),  -->   (12, 22, 32, 42),
(31, 32        ),        (13, 23,     43),
(41, 42, 43, 44),        (    24,     44)

(为了更好的图形对齐添加了空格.)

我设法通过清除 zip_longest 之后的 fillvalue 来编写一个粗略的解决方案.

I managed to compose a crude a solution by cleaning out the fillvalues after zip_longest.

def zip_discard(*iterables, sentinel = object()):
    return map(
            partial(filter, partial(is_not, sentinel)), 
            zip_longest(*iterables, fillvalue=sentinel))

有没有办法在不引入哨兵的情况下做到这一点?这可以使用 yield 改进吗?哪种方法看起来最有效?

Is there a way to do this without introducing the sentinels to begin with? Can this be improved using yield? Which approach seems most efficient?

推荐答案

zipzip_longest 都被设计为总是生成等长的元组,你可以定义自己的不关心 len 的生成器,如下所示:

Both zip and zip_longest were designed to always generate tuples of equal length, you can define your own generator that doesn't care about the len with something like this:

def _one_pass(iters):
    for it in iters:
        try:
            yield next(it)
        except StopIteration:
            pass #of some of them are already exhausted then ignore it.

def zip_varlen(*iterables):
    iters = [iter(it) for it in iterables]
    while True: #broken when an empty tuple is given by _one_pass
        val = tuple(_one_pass(iters))
        if val:
            yield val
        else:
            break

如果压缩在一起的数据相当大,那么每次跳过耗尽的迭代器可能会很昂贵,从 _one_pass 中的 iters 中删除完成的迭代器可能更有效代码>函数如下:

If the data being zipped together is fairly large then skipping the exhausted iterators every time can be expensive, it may be more efficient to remove the finished iterators from iters in the _one_pass function like this:

def _one_pass(iters):
    i = 0
    while i<len(iters):
        try:
            yield next(iters[i])
        except StopIteration:
            del iters[i]
        else:
            i+=1

这两个版本都不需要创建中间结果或使用临时填充值.

both of these versions would remove the need to create intermediate results or use temporary filler values.

这篇关于没有填充值的 zip_longest的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆