Existe-t-il une fonction de type zip qui se remplit sur la plus grande longueur en Python?

170

Existe-t-il une fonction intégrée qui fonctionne comme zip()mais qui remplira les résultats de sorte que la longueur de la liste résultante soit la longueur de l' entrée la plus longue plutôt que celle de l' entrée la plus courte ?

>>> 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
la source

Réponses:

243

Dans Python 3, vous pouvez utiliser itertools.zip_longest

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

Vous pouvez ajouter une valeur différente de celle Noneen utilisant le fillvalueparamètre:

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

Avec Python 2, vous pouvez soit utiliser itertools.izip_longest(Python 2.6+), soit utiliser mapavec None. C'est une fonctionnalité peu connue demap (mais mapmodifiée dans Python 3.x, donc cela ne fonctionne que dans Python 2.x).

>>> map(None, a, b, c)
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
Nadia Alramli
la source
3
N'avons-nous pas de solution Python 3 non itertools?
PascalVKooten
3
@PascalvKooten ce n'est pas obligatoire. itertoolsest de toute façon un module C intégré.
Antti Haapala
82

Pour Python 2.6x, utilisez les itertoolsmodules izip_longest.

Pour Python 3, utilisez à la zip_longestplace (pas de début i).

>>> list(itertools.izip_longest(a, b, c))
[('a1', 'b1', 'c1'), (None, 'b2', 'c2'), (None, 'b3', None)]
SilentGhost
la source
8
Si vous souhaitez rendre votre code compatible python 2 et python 3, vous pouvez utiliser à la six.moves.zip_longestplace.
Gamrix
5

solution Python 3 non itertools:

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
la source
2

non itertools Ma solution Python 2:

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

J'utilise un tableau 2D mais le concept est le même en utilisant 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
la source
2
Veuillez ajouter une explication sur la raison pour laquelle ce code fonctionne. Ou pourquoi c'est la bonne réponse
Suit Boy Apps