Gibt es eine zip-ähnliche Funktion, die in Python auf die längste Länge aufgefüllt wird?

170

Gibt es eine integrierte Funktion, die wie zip()folgt funktioniert, aber die Ergebnisse auffüllt, sodass die Länge der resultierenden Liste eher der Länge der längsten Eingabe als der kürzesten Eingabe entspricht?

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

Antworten:

243

In Python 3 können Sie verwenden itertools.zip_longest

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

Sie können mit einem anderen Wert als Nonemit dem folgenden fillvalueParameter auffüllen:

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

Mit Python 2 können Sie entweder itertools.izip_longest(Python 2.6+) oder mapmit verwenden None. Es ist eine wenig bekannte Funktion vonmap (wurde jedoch mapin Python 3.x geändert, sodass dies nur in Python 2.x funktioniert).

>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
Nadia Alramli
quelle
3
Haben wir keine Python 3-Lösung ohne itertools?
PascalVKooten
3
@PascalvKooten ist nicht erforderlich. itertoolsist sowieso ein eingebautes C-Modul.
Antti Haapala
82

Verwenden Sie für Python 2.6x itertoolsModule izip_longest.

Verwenden Sie zip_longeststattdessen Python 3 (kein führendes i).

>>> list(itertools.izip_longest(a, b, c))
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
SilentGhost
quelle
8
Wenn Sie Ihren Code sowohl für Python 2 als auch für Python 3 kompatibel machen möchten, können Sie ihn six.moves.zip_longeststattdessen verwenden.
Gamrix
5

Nicht-Itertools Python 3-Lösung:

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
quelle
2

non itertools Meine Python 2-Lösung:

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

Ich benutze ein 2d Array, aber das Konzept ist das gleiche mit 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
quelle
2
Bitte fügen Sie eine Erklärung hinzu, warum dieser Code funktioniert. Oder warum es die richtige Antwort ist
Suit Boy Apps