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

我与影子孤独终老i 提交于 2019-12-22 08:52:56

问题


Is there a built-in function that works like zip(), but fills the results so that the length of the resulting list is the length of the longest input and fills the list from the left with e.g. None?

There is already an answer using zip_longest from itertools module and the corresponding question is very similar to this. But with zip_longest it seems that you can only fill missing data from the right.

Here might be a use case for that, assuming we have names stored only like this (it's just an example):

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

There is no other permutation like (["Poppins", "Mary"], ["Poppins", "Dr", "Mary"]) and so on.

How can I get results like this using built-in functions?

>>> 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}

回答1:


Use zip_longest but reverse lists.

Example:

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}

On your use cases:

>>> 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}



回答2:


Simply use zip_longest and read the arguments in the reverse direction:

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}

Since the zip* functions need to be able to work on general iterables, they don't support filling "from the left", because you'd need to exhaust the iterable first. Here we can just flip things ourselves.




回答3:


The generic "magic zip" generator function with a variable number of args (which only uses lazy-evaluation functions and no python loops):

import itertools

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

testing (of course in the case of a dict build, only 2 params are needed):

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

result:

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



回答4:


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


来源:https://stackoverflow.com/questions/51878354/zip-like-built-in-function-filling-unequal-lengths-from-left-with-none-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!