Python Outerzip/zip最长函数(具有多个填充值)

Python Outerzip/zip最长函数(具有多个填充值),python,Python,是否有一个Python函数“outer-zip”,它是的扩展,每个iterable都有不同的默认值 a = [1, 2, 3] # associate a default value 0 b = [4, 5, 6, 7] # associate b default value 1 zip(a,b) # [(1, 4), (2, 5), (3, 6)] outerzip((a, 0), (b, 1)) = [(1, 4), (2, 5), (3, 6), (0, 7)] outerzip

是否有一个Python函数“outer-zip”,它是的扩展,每个iterable都有不同的默认值

a = [1, 2, 3]   # associate a default value 0
b = [4, 5, 6, 7] # associate b default value 1

zip(a,b)  # [(1, 4), (2, 5), (3, 6)]

outerzip((a, 0), (b, 1)) = [(1, 4), (2, 5), (3, 6), (0, 7)]
outerzip((b, 0), (a, 1)) = [(4, 1), (5, 2), (6, 3), (7, 1)]
我几乎可以使用复制此outerzip函数,但只有
None
作为默认值:

注1:内置函数接受任意数量的iterables,因此
outerzip
函数也应如此。(例如,人们应该能够计算
outerzip((a,0)、(a,0)、(b,1))
类似于
zip(a,a,b)
map(无,a,a,b)

注2:我用的样式说“outer-zip”,但这可能不是正确的术语。

它的名称(在python-3.x中):


此功能可通过扩展每个输入列表和压缩来定义:

def outerzip(*args):
    # args = (a, default_a), (b, default_b), ...
    max_length = max( map( lambda s: len(s[0]), args))
    extended_args = [ s[0] + [s[1]]*(max_length-len(s[0])) for s in args ]
    return zip(*extended_args)

outerzip((a, 0), (b, 1)) # [(1, 4), (2, 5), (3, 6), (0, 7)]
您可以使用它来支持您的通用iterables用例

from itertools import chain, repeat

class OuterZipStopIteration(Exception):
    pass

def outer_zip(*args):
    count = len(args) - 1

    def sentinel(default):
        nonlocal count
        if not count:
            raise OuterZipStopIteration
        count -= 1
        yield default

    iters = [chain(p, sentinel(default), repeat(default)) for p, default in args]
    try:
        while iters:
            yield tuple(map(next, iters))
    except OuterZipStopIteration:
        pass


print(list(outer_zip( ("abcd", '!'), 
                      ("ef", '@'), 
                      (map(int, '345'), '$') )))

我能给a和b换一个不同的填充值吗?@hayden:那怎么行?调用
zip\u longest
w/两个不同的
fillvalue
s取决于
a
b
的长度。如果len(a)
列表(zip\u longest(a,b,fillvalue=1,如果len(a)>len(b)else 0),您的答案不一致,因为它同时使用了
zip\u longest()
izip\u longest()
…一个人应该能够计算出
outerzip(a,0,a,2,b,1)
?这是个好问题!我不确定这是否有意义(我个人认为这不会发生,因为列表的元素总是特定类型的,因此有一个隐含的默认值),但我不确定在一般的
outerzip
函数中…使用
map
的有用技巧。我想你的问题最好用“zip_longest()“有多个填充值?”因为它被标记为“Python”。@martineau重新命名,保留了这两个值(尽管我想zip_longest是一个更具Python风格的名称!)您使用的
nonlocal
使其成为一个仅适用于Python 3的解决方案——尽管Python 2.x版本也可能很容易编写。@martineau:请参阅如何在Python 2中替换
nonlocal
。是的,我知道有一些变通方法。事实上,在for
izip_longest()
中,一个用于纯Python代码中的
计数器
变量,它说这是等效的——这就是为什么我说创建2.x版本可能是一件相对容易的事情。我发表评论是因为OP的问题没有标记为Python-3.x。这个函数非常聪明,值得赏金!回顾过去,有一个小问题是,调用子函数“sentinel”有什么原因吗?@AndyHayden:可能是为了传达它是一个“sentinel值”。
def outerzip(*args):
    # args = (a, default_a), (b, default_b), ...
    max_length = max( map( lambda s: len(s[0]), args))
    extended_args = [ s[0] + [s[1]]*(max_length-len(s[0])) for s in args ]
    return zip(*extended_args)

outerzip((a, 0), (b, 1)) # [(1, 4), (2, 5), (3, 6), (0, 7)]
from itertools import chain, repeat

class OuterZipStopIteration(Exception):
    pass

def outer_zip(*args):
    count = len(args) - 1

    def sentinel(default):
        nonlocal count
        if not count:
            raise OuterZipStopIteration
        count -= 1
        yield default

    iters = [chain(p, sentinel(default), repeat(default)) for p, default in args]
    try:
        while iters:
            yield tuple(map(next, iters))
    except OuterZipStopIteration:
        pass


print(list(outer_zip( ("abcd", '!'), 
                      ("ef", '@'), 
                      (map(int, '345'), '$') )))