是否有一个内置函数,工作类似zip(),但将填充结果,使结果列表的长度是最长的输入而不是最短的输入的长度?
>>> a = ['a1']
>>> b = ['b1', 'b2', 'b3']
>>> c = ['c1', 'c2']
>>> zip(a, b, c)
[('a1', 'b1', 'c1')]
>>> What command goes here?
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
是否有一个内置函数,工作类似zip(),但将填充结果,使结果列表的长度是最长的输入而不是最短的输入的长度?
>>> a = ['a1']
>>> b = ['b1', 'b2', 'b3']
>>> c = ['c1', 'c2']
>>> zip(a, b, c)
[('a1', 'b1', 'c1')]
>>> What command goes here?
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
当前回答
为了补充已经给出的答案,以下内容适用于任何可迭代对象,不使用itertools,回答@ProdIssue的问题:
def zip_longest(*iterables, default_value):
iterators = tuple(iter(i) for i in iterables)
sentinel = object()
while True:
new = tuple(next(i, sentinel) for i in iterators)
if all(n is sentinel for n in new):
return
yield tuple(default_value if n is sentinel else n for n in new)
需要使用sentinel,以便产生default_value的迭代器不会被错误地标识为空。
其他回答
non itertools Python 3 解决方案:
def zip_longest(*lists):
def g(l):
for item in l:
yield item
while True:
yield None
gens = [g(l) for l in lists]
for _ in range(max(map(len, lists))):
yield tuple(next(g) for g in gens)
为了补充已经给出的答案,以下内容适用于任何可迭代对象,不使用itertools,回答@ProdIssue的问题:
def zip_longest(*iterables, default_value):
iterators = tuple(iter(i) for i in iterables)
sentinel = object()
while True:
new = tuple(next(i, sentinel) for i in iterators)
if all(n is sentinel for n in new):
return
yield tuple(default_value if n is sentinel else n for n in new)
需要使用sentinel,以便产生default_value的迭代器不会被错误地标识为空。
在Python 3中,您可以使用itertools.zip_longest
>>> list(itertools.zip_longest(a, b, c))
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
你可以使用fillvalue参数填充不同于None的值:
>>> list(itertools.zip_longest(a, b, c, fillvalue='foo'))
[('a1', 'b1', 'c1'), ('foo', 'b2', 'c2'), ('foo', 'b3', 'foo')]
在Python 2中,你可以使用itertools。izip_longest (Python 2.6+),或者可以使用map和None。这是map的一个鲜为人知的特性(但是map在Python 3中改变了。x,所以这只适用于Python 2.x)。
>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
除了接受的答案外,如果你使用的可迭代对象可能长度不同,但不应该是,建议将strict=True传递给zip()(自Python 3.10起支持)。
引用文件:
zip() is often used in cases where the iterables are assumed to be of equal length. In such cases, it’s recommended to use the strict=True option. Its output is the same as regular zip(): >>> list(zip(('a', 'b', 'c'), (1, 2, 3), strict=True)) [('a', 1), ('b', 2), ('c', 3)] Unlike the default behavior, it checks that the lengths of iterables are identical, raising a ValueError if they aren’t: >>> list(zip(range(3), ['fee', 'fi', 'fo', 'fum'], strict=True)) Traceback (most recent call last): ... ValueError: zip() argument 2 is longer than argument 1 Without the strict=True argument, any bug that results in iterables of different lengths will be silenced, possibly manifesting as a hard-to-find bug in another part of the program.
我使用一个2d数组,但概念是类似的使用python 2.x:
if len(set([len(p) for p in printer])) > 1:
printer = [column+['']*(max([len(p) for p in printer])-len(column)) for column in printer]