是否有一个类似拉链的功能,垫到最长的长度?

是否有一个内置函数像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)]
113097 次浏览

对于Python 2.6x,使用itertools模块的izip_longest

对于Python 3,使用zip_longest代替(不使用i前导)。

>>> list(itertools.izip_longest(a, b, c))
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]

在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+),也可以使用mapNone。它是鲜为人知的map的特性(但map在Python 3中改变了。x,所以这只适用于Python 2.x)。

>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]

非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)

我的Python 2解决方案:

if len(list1) < len(list2):
list1.extend([None] * (len(list2) - len(list1)))
else:
list2.extend([None] * (len(list1) - len(list2)))

我使用一个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]

除了接受的答案外,如果你使用的可迭代对象可能长度不同,而不应该是,建议将strict=True传递给zip()(自Python 3.10起支持)。

引用文件:

zip()通常用于假定可迭代对象为的情况 长度相等。在这种情况下,建议使用strict=True 选择。它的输出与常规zip()相同:

>>> list(zip(('a', 'b', 'c'), (1, 2, 3), strict=True))
[('a', 1), ('b', 2), ('c', 3)]

与默认行为不同,它检查 可迭代对象的长度是相同的,如果它们 不是:< / p >

>>> list(zip(range(3), ['fee', 'fi', 'fo', 'fum'], strict=True))
Traceback (most recent call last):
...
ValueError: zip() argument 2 is longer than argument 1

没有strict=True参数,任何错误 这将导致不同长度的可迭代对象被静音, 的其他部分可能表现为难以发现的错误 程序。< / p >

为了补充已经给出的答案,下面的方法适用于任何可迭代对象,并且不使用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的迭代器不会被错误地标识为空。

只是使用迭代器,没什么特别的。

def zip_longest(*iterables):
items = 0
for iterable in iterables:
items = max(items, len(iterable))


iters = [iter(iterable) for iterable in iterables]
while items:
yield (*[next(i, None) for i in iters],)
items -= 1