web-dev-qa-db-fra.com

Zipper des listes inégales en python dans une liste qui ne supprime aucun élément d'une liste plus longue en cours de compression

J'ai deux listes

a = [1,2,3]
b = [9,10]

Je veux combiner (Zip) ces deux listes en une liste c telle que 

c = [(1,9), (2,10), (3, )]

Y at-il une fonction dans la bibliothèque standard en Python pour faire cela?

28
Dilawar

Ce que vous cherchez, c'est itertools.izip_longest

Dans Python3.x, vous recherchez itertools.Zip_longest

>>> a = [1,2,3]
>>> b = [9,10]
>>> for i in itertools.izip_longest(a,b): print i
... 
(1, 9)
(2, 10)
(3, None)

EDIT 1 : Si vous voulez vraiment vous débarrasser de la Nones, vous pouvez essayer:

>>> for i in (filter(None, pair) for pair in itertools.izip_longest(a,b)): print i
(1, 9)
(2, 10)
(3,)

EDIT 2 : En réponse au commentaire de steveha:

filter(lambda p: p is not None, pair) for pair in itertools.izip_longest(a,b)
37
inspectorG4dget

Une autre façon est map:

a = [1, 2, 3]
b = [9, 10]
c = map(None, a, b)

Bien que cela contienne aussi (3, None) au lieu de (3,). Pour ce faire, voici une ligne amusante:

c = (Tuple(y for y in x if y is not None) for x in map(None, a, b))
9
Ry-

Il n'est pas trop difficile d'écrire simplement le Python explicite pour effectuer l'opération souhaitée:

def izip_short(a, b):
    ia = iter(a)
    ib = iter(b)
    for x in ia:
        try:
            y = next(ib)
            yield (x, y)
        except StopIteration:
            yield (x,)
            break
    for x in ia:
        yield (x,)
    for y in ib:
        yield (None, y)

a = [1, 2, 3]
b = [9, 10]
list(izip_short(a, b))
list(izip_short(b, a))

Je ne savais pas trop comment vous voudriez gérer la séquence b étant plus longue que la séquence a, alors je me contentais de la placer dans None pour la première valeur du Tuple dans ce cas.

Obtenez un itérateur explicite pour chaque séquence. Exécutez l'itérateur a en tant que boucle for tout en utilisant manuellement next(ib) pour obtenir la valeur suivante de la séquence b. Si nous obtenons une StopIteration sur la séquence b, nous cassons la boucle et ensuite for x in ia: récupère le reste de la séquence a; après cela, for y in ib: ne fera rien car cet itérateur est déjà épuisé. Sinon, si la première boucle for x in ia: épuise l'itérateur a, le deuxième for x in ia: ne fait rien, mais il pourrait rester des valeurs dans la séquence b et la boucle for y in ib: les collectera.

2
steveha

Une seule ligne:

c = Zip(a, b) + [(x,) for x in a[len(b):]] + [(x,) for x in b[len(a):]]

Si vous voulez réutiliser ceci:

def mergeUsNicely(a, b):
    def tupleMe(val):
        return (val,)
    return Zip(a, b) + map(tupleMe, a[len(b):]) + map(tupleMe, b[len(a):])
1
SeeknInspYre