web-dev-qa-db-fra.com

Comment convertir une liste de tuples en plusieurs listes?

Supposons que j'ai une liste de tuples et que je souhaite convertir en plusieurs listes.

Par exemple, la liste des tuples est

[(1,2),(3,4),(5,6),]

Existe-t-il une fonction intégrée dans Python qui la convertit en:

[1,3,5],[2,4,6]

Cela peut être un programme simple. Mais je suis simplement curieux de savoir l'existence d'une telle fonction intégrée en Python.

87
xiaohan2012

La fonction intégrée Zip() fera presque ce que vous voulez:

>>> Zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]

La seule différence est que vous obtenez des tuples au lieu de listes. Vous pouvez les convertir en listes en utilisant

map(list, Zip(*[(1, 2), (3, 4), (5, 6)]))
131
Sven Marnach

Depuis les documents python :

Zip () en conjonction avec l'opérateur * peut être utilisé pour décompresser une liste:

Exemple spécifique:

>>> Zip((1,3,5),(2,4,6))
[(1, 2), (3, 4), (5, 6)]
>>> Zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]

Ou, si vous voulez vraiment des listes:

>>> map(list, Zip(*[(1, 2), (3, 4), (5, 6)]))
[[1, 3, 5], [2, 4, 6]]
38
Claudiu

Utilisation:

a = [(1,2),(3,4),(5,6),]    
b = Zip(*a)
>>> [(1, 3, 5), (2, 4, 6)]
8
Artsiom Rudzenka

franklsf95 opte pour la performance dans sa réponse et opte pour list.append(), mais ils ne sont pas optimaux.

En ajoutant des compréhensions de liste, je me suis retrouvé avec ce qui suit:

def t1(zs):
    xs, ys = Zip(*zs)
    return xs, ys

def t2(zs):
    xs, ys = [], []
    for x, y in zs:
        xs.append(x)
        ys.append(y)
    return xs, ys

def t3(zs):
    xs, ys = [x for x, y in zs], [y for x, y in zs]
    return xs, ys

if __== '__main__':
    from timeit import timeit
    setup_string='''\
N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(Zip(xs, ys))
from __main__ import t1, t2, t3
'''
    print(f'Zip:\t\t{timeit('t1(zs)', setup=setup_string, number=1000)}')
    print(f'append:\t\t{timeit('t2(zs)', setup=setup_string, number=1000)}')
    print(f'list comp:\t{timeit('t3(zs)', setup=setup_string, number=1000)}')

Cela a donné le résultat:

Zip:            122.11585397789766
append:         356.44876132614047
list comp:      144.637765085659

Donc, si vous recherchez des performances, vous devriez probablement utiliser Zip() bien que les compréhensions de liste ne soient pas trop loin derrière. Les performances de append sont en fait assez médiocres en comparaison.

4
Baldrickk

Ajout à la réponse de Claudiu et Claudiu et puisque la carte doit être importée d'itertools dans python 3, vous utilisez également une compréhension de liste comme:

[[*x] for x in Zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
0
Quickbeam2k1

En plus de la réponse de Claudiu, vous pouvez utiliser:

>>>a, b = map(list, Zip(*[(1, 2), (3, 4), (5, 6)]))
>>>a
[1,3,5]
>>>b
[2,4,6]

Édité selon @Peyman mohseni kiasari

0
Eric Lin

Malgré *Zip étant plus Pythonic, le code suivant a de bien meilleures performances:

xs, ys = [], []
for x, y in zs:
    xs.append(x)
    ys.append(y)

De plus, lorsque la liste d'origine zs est vide, *Zip augmentera, mais ce code peut gérer correctement.

Je viens de faire une petite expérience et voici le résultat:

Using *Zip:     1.54701614s
Using append:   0.52687597s

En l'exécutant plusieurs fois, append est 3x - 4x plus rapide que Zip! Le script de test est ici:

#!/usr/bin/env python3
import time

N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(Zip(xs, ys))

t1 = time.time()

xs_, ys_ = Zip(*zs)
print(len(xs_), len(ys_))

t2 = time.time()

xs_, ys_ = [], []
for x, y in zs:
    xs_.append(x)
    ys_.append(y)
print(len(xs_), len(ys_))

t3 = time.time()

print('Using *Zip:\t{:.8f}s'.format(t2 - t1))
print('Using append:\t{:.8f}s'.format(t3 - t2))

Ma Python Version:

Python 3.6.3 (default, Oct 24 2017, 12:18:40)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
0
franklsf95