Есть ли zip-подобная функция, которая увеличивает длину Python?

170

Есть ли встроенная функция, которая работает как, 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)]
Марк Харрисон
источник

Ответы:

243

В 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с None. Это малоизвестная особенностьmap (но mapизменена в Python 3.x, так что это работает только в Python 2.x).

>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
Надя Алрамли
источник
3
Разве у нас нет решения Python 3 без itertools?
PascalVKooten
3
@PascalvKooten не требуется. itertoolsв любом случае это встроенный модуль C
Антти Хаапала
82

Для 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)]
SilentGhost
источник
8
Если вы хотите, чтобы ваш код был совместим с Python 2 и Python 3, вы можете использовать six.moves.zip_longestвместо этого.
Gamrix
5

Решение, отличное от 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)
dansalmo
источник
2

Решение, не относящееся к itertools My Python 2:

if len(list1) < len(list2):
    list1.extend([None] * (len(list2) - len(list1)))
else:
    list2.extend([None] * (len(list1) - len(list2)))
Хелтон Верник
источник
0

Я использую 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]
user12204058
источник
2
Пожалуйста, добавьте объяснение, почему этот код работает. Или почему это правильный ответ
Suit Boy Apps