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.
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)]))
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]]
Utilisation:
a = [(1,2),(3,4),(5,6),]
b = Zip(*a)
>>> [(1, 3, 5), (2, 4, 6)]
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.
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]]
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
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.