Comment fusionner des listes en une liste de tuples?

298

Quelle est l'approche Pythonic pour atteindre les objectifs suivants?

# Original lists:

list_a = [1, 2, 3, 4]
list_b = [5, 6, 7, 8]

# List of tuples from 'list_a' and 'list_b':

list_c = [(1,5), (2,6), (3,7), (4,8)]

Chaque membre de list_cest un tuple, dont le premier membre est de list_aet le second est de list_b.

rubayeet
la source

Réponses:

443

En Python 2:

>>> list_a = [1, 2, 3, 4]
>>> list_b = [5, 6, 7, 8]
>>> zip(list_a, list_b)
[(1, 5), (2, 6), (3, 7), (4, 8)]

En Python 3:

>>> list_a = [1, 2, 3, 4]
>>> list_b = [5, 6, 7, 8]
>>> list(zip(list_a, list_b))
[(1, 5), (2, 6), (3, 7), (4, 8)]
TU
la source
77
vous devez savoir que la fonction zip s'arrête à la fin de la liste la plus courte, ce qui n'est pas toujours ce que vous voulez. le itertoolsmodule définit une zip_longest()méthode qui s'arrête à la fin de la liste la plus longue, remplissant les valeurs manquantes avec quelque chose que vous fournissez comme paramètre.
Adrien Plisson
5
@Adrien: bravo pour votre commentaire applicable. Pour Python 2.x, s/zip_longest()/izip_longest(). Renommé en Python 3.x en zip_longest().
mechanical_meat
puis-je créer [(1,5), (1,6), (1,7), (1,8), (2,5), (2,6), etc.] à l'aide de la commande zip?
Mona Jalal
3
@MonaJalal: non, ce n'est pas l'appariement, c'est la création du produit des listes. itertools.product()est-ce que.
Martijn Pieters
2
note, au moins en python3.6 zip ne renvoie pas de liste. Vous avez donc besoin de list (zip (list_a, list_b)) à la place
Supamee
141

En python 3.0, zip renvoie un objet zip. Vous pouvez en obtenir une liste en appelant list(zip(a, b)).

Lodewijk
la source
3
Cela peut être trivial, mais sachez que l'utiliser directement dans une boucle for vous donne un générateur qui sera épuisé après l'avoir utilisé une fois. Enregistrez dans une variable si vous souhaitez l'utiliser plus souvent
Hakaishin
13

Vous pouvez utiliser la carte lambda

a = [2,3,4]
b = [5,6,7]
c = map(lambda x,y:(x,y),a,b)

Cela fonctionnera également si la longueur des listes originales ne correspond pas

Chevalier noir
la source
1
Pourquoi utiliser un lambda? map(None, a,b)
Padraic Cunningham
Je n'ai accès qu'à python 3.5.
Dark Knight
3
Si vous utilisiez python3, alors c ne serait pas une liste, ce serait un objet de carte.Utiliser également un lambda sera beaucoup moins efficace que de simplement zipper, si vous avez des listes de longueurs différentes et que vous souhaitez gérer cela, vous utiliserez izip_longest / zip_longest
Padraic Cunningham
8

Vous êtes à la recherche de la fonction zip intégrée .

Mizipzor
la source
6

Je ne sais pas si c'est une manière pythonique ou pas mais cela semble simple si les deux listes ont le même nombre d'éléments:

list_a = [1, 2, 3, 4]

list_b = [5, 6, 7, 8]

list_c=[(list_a[i],list_b[i]) for i in range(0,len(list_a))]
Vipin
la source
5

Je sais que c'est une vieille question à laquelle on a déjà répondu, mais pour une raison quelconque, je veux toujours publier cette solution alternative. Je sais qu'il est facile de découvrir quelle fonction intégrée fait la "magie" dont vous avez besoin, mais cela ne fait pas de mal de savoir que vous pouvez le faire vous-même.

>>> list_1 = ['Ace', 'King']
>>> list_2 = ['Spades', 'Clubs', 'Diamonds']
>>> deck = []
>>> for i in range(max((len(list_1),len(list_2)))):
        while True:
            try:
                card = (list_1[i],list_2[i])
            except IndexError:
                if len(list_1)>len(list_2):
                    list_2.append('')
                    card = (list_1[i],list_2[i])
                elif len(list_1)<len(list_2):
                    list_1.append('')
                    card = (list_1[i], list_2[i])
                continue
            deck.append(card)
            break
>>>
>>> #and the result should be:
>>> print deck
>>> [('Ace', 'Spades'), ('King', 'Clubs'), ('', 'Diamonds')]
Kruger
la source
2
Changer une des listes d'entrée (si elles diffèrent en longueur) n'est pas un bon effet secondaire. De plus, les deux affectations carddans le if-elifne sont pas nécessaires, c'est pourquoi vous avez le continue. (En fait, sans que continuevous n'auriez pas à modifier les listes: les deux missions mentionnées précédemment devraient alors être conservés et deviennent card = (list_1[i], '')et card = ('', list_2[1])respectivement.)
ᴠɪɴᴄᴇɴᴛ
5

La sortie que vous avez montrée dans l'énoncé du problème n'est pas le tuple mais la liste

list_c = [(1,5), (2,6), (3,7), (4,8)]

vérifier

type(list_c)

considérant que vous voulez que le résultat soit un tuple de list_a et list_b, faites

tuple(zip(list_a,list_b)) 
cyborg
la source
De mon point de vue, cela semble être ce que je recherche et fonctionne bien pour les deux (liste et tuple). Parce que lorsque vous utilisez l' impression , vous verrez la bonne valeur (comme prévu et mentionné par @cyborg et @Lodewijk) et rien lié à l' objet tel que: <map object at 0x000001F266DCE5C0>ou <zip object at 0x000002629D204C88>. Au moins, la solution concernant la carte et le zip (seul) semble être incomplète (ou trop compliquée) pour moi.
Wagner_SOFC
1
La question indique qu'ils veulent une liste de tuples et non un tuple de tuples.
goryh
1

Une alternative sans utiliser zip:

list_c = [(p1, p2) for idx1, p1 in enumerate(list_a) for idx2, p2 in enumerate(list_b) if idx1==idx2]

Dans le cas où l'on veut obtenir non seulement des tuples 1er au 1er, 2e au 2e ... mais toutes les combinaisons possibles des 2 listes, cela se ferait avec

list_d = [(p1, p2) for p1 in list_a for p2 in list_b]
J0ANMM
la source