是否有类似 zip 的函数可以填充到最长长度?
- 2024-12-17 08:31:00
- admin 原创
- 155
问题描述:
是否有一个内置函数可以正常工作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)]
解决方案 1:
在 Python 3 中你可以使用itertools.zip_longest
>>> list(itertools.zip_longest(a, b, c))
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
None
您可以使用与使用参数不同的值进行填充fillvalue
:
>>> 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
with None
。这是一个鲜为人知的功能map
(但map
在 Python 3.x 中有所更改,因此仅适用于 Python 2.x)。
>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
解决方案 2:
对于 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)]
解决方案 3:
除了接受的答案之外,如果您正在使用长度可能不同但不应该不同的可迭代对象,建议传递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)]
与默认行为不同,它会检查可迭代对象的长度是否相同,
ValueError
如果不一致,则会引发:>>> 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
参数,任何导致可迭代对象长度不同的错误都会被忽略,可能表现为程序另一部分中难以发现的错误。
解决方案 4:
非 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)
解决方案 5:
非 itertools 我的 Python 2 解决方案:
if len(list1) < len(list2):
list1.extend([None] * (len(list2) - len(list1)))
else:
list2.extend([None] * (len(list1) - len(list2)))
解决方案 6:
除了已经给出的答案之外,以下内容适用于任何可迭代且不使用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
就不会被错误地识别为空。
解决方案 7:
只需使用迭代器,没什么特别的。
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
解决方案 8:
我使用二维数组,但概念与使用 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]
扫码咨询,免费领取项目管理大礼包!