类似 zip() 的内置函数,用 None 值从左边填充不等长度

zip()-like built-in function filling unequal lengths from left with None value

是否有一个类似于 zip() 的内置函数,但是填充结果使得结果列表的长度是最长输入的长度并从左侧填充列表 例如None?

已经有一个answer using zip_longest from itertools module and the corresponding question与此非常相似。但是 zip_longest 似乎只能从右边填充缺失的数据。

这可能是一个用例,假设我们只像这样存储名称(这只是一个例子):

header = ["title", "firstname", "lastname"]
person_1 = ["Dr.", "Joe", "Doe"]
person_2 = ["Mary", "Poppins"]
person_3 = ["Smith"]

没有其他排列,如 (["Poppins", "Mary"], ["Poppins", "Dr", "Mary"]) 等等。

如何使用内置函数获得这样的结果?

>>> dict(magic_zip(header, person_1))
{'title': 'Dr.', 'lastname': 'Doe', 'firstname': 'Joe'}
>>> dict(magic_zip(header, person_2))
{'title': None, 'lastname': 'Poppins', 'firstname': 'Mary'}
>>> dict(magic_zip(header, person_3))
{'title': None, 'lastname': 'Smith', 'firstname': None}

使用zip_longest但反转列表。

示例

from itertools import zip_longest

header = ["title", "firstname", "lastname"]
person_1 = ["Dr.", "Joe", "Doe"]
person_2 = ["Mary", "Poppins"]
person_3 = ["Smith"]

print(dict(zip_longest(reversed(header), reversed(person_2))))
# {'lastname': 'Poppins', 'firstname': 'Mary', 'title': None}

关于您的用例:

>>> dict(zip_longest(reversed(header), reversed(person_1))) 
{'title': 'Dr.', 'lastname': 'Doe', 'firstname': 'Joe'}
>>> dict(zip_longest(reversed(header), reversed(person_2)))
{'lastname': 'Poppins', 'firstname': 'Mary', 'title': None} 
>>> dict(zip_longest(reversed(header), reversed(person_3))) 
{'lastname': 'Smith', 'firstname': None, 'title': None}

只需使用zip_longest并反向读取参数:

In [20]: dict(zip_longest(header[::-1], person_1[::-1]))
Out[20]: {'lastname': 'Doe', 'firstname': 'Joe', 'title': 'Dr.'}

In [21]: dict(zip_longest(header[::-1], person_2[::-1]))
Out[21]: {'lastname': 'Poppins', 'firstname': 'Mary', 'title': None}

In [22]: dict(zip_longest(header[::-1], person_3[::-1]))
Out[22]: {'lastname': 'Smith', 'firstname': None, 'title': None}

由于 zip* 函数需要能够处理一般的可迭代对象,因此它们不支持填充 "from the left",因为您需要先耗尽可迭代对象。在这里我们可以自己动手。

def magic_zip(*lists):
    max_len = max(map(len, lists))
    return zip(*([None] * (max_len - len(l)) + l for l in lists))

具有可变数量参数的通用 "magic zip" 生成器函数(仅使用惰性求值函数,没有 python 循环):

import itertools

def magic_zip(*args):
    return itertools.zip_longest(*map(reversed,args))

测试(当然在dict构建的情况下,只需要2个参数):

for p in (person_1,person_2,person_3):
    print(dict(magic_zip(header,p)))

结果:

{'lastname': 'Doe', 'title': 'Dr.', 'firstname': 'Joe'}
{'lastname': 'Poppins', 'title': None, 'firstname': 'Mary'}
{'lastname': 'Smith', 'title': None, 'firstname': None}