¿Existe una función de tipo zip que se adapta a la longitud más larga en Python?

170

¿Existe una función incorporada que funcione zip()pero que rellene los resultados para que la longitud de la lista resultante sea la longitud de la entrada más larga en lugar de la más corta ?

>>> 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)]
Mark Harrison
fuente

Respuestas:

243

En Python 3 puedes usar itertools.zip_longest

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

Puede rellenar con un valor diferente Noneal usar el fillvalueparámetro:

>>> list(itertools.zip_longest(a, b, c, fillvalue='foo'))
[('a1', 'b1', 'c1'), ('foo', 'b2', 'c2'), ('foo', 'b3', 'foo')]

Con Python 2 puede usar itertools.izip_longest(Python 2.6+), o puede usar mapcon None. Es una característicamap poco conocida de (pero mapcambió en Python 3.x, por lo que solo funciona en Python 2.x).

>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
Nadia Alramli
fuente
3
¿No tenemos una solución Python 3 que no sea itertools?
PascalVKooten
3
@PascalvKooten no es obligatorio. itertoolses un módulo C incorporado de todos modos.
Antti Haapala
82

Para Python 2.6x, use los itertoolsmódulos izip_longest.

Para Python 3, use zip_longesten su lugar (sin encabezado i).

>>> list(itertools.izip_longest(a, b, c))
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
SilentGhost
fuente
8
En caso de que desee que su código sea compatible tanto con python 2 como con python 3, puede usarlo six.moves.zip_longest.
Gamrix
5

Solución no 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
fuente
2

Solución no itertools My Python 2:

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

Estoy usando una matriz 2d pero el concepto es similar al uso de 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]
usuario12204058
fuente
2
Agregue una explicación de por qué funciona este código. O por qué es la respuesta correcta
Suit Boy Apps