2011-11-10 1 views
53

Supponiamo di avere un elenco di tuple e che voglio convertire in più elenchi.convertire l'elenco di tuple in più elenchi in Python

Ad esempio, l'elenco di tuple c'è

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

è un qualsiasi funzione built-in in Python che converte in:

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

Questo può essere un semplice programma. Ma sono solo curioso dell'esistenza di tale funzione integrata in Python.

risposta

82

La funzione built-in zip() sarà quasi fare quello che vuoi:

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

L'unica differenza è che si ottiene tuple invece di liste. È possibile convertire in liste utilizzando

map(list, zip(*[(1, 2), (3, 4), (5, 6)])) 
30

Dal python docs:

zip() in collaborazione con l'operatore * può essere utilizzato per decomprimere un elenco:

esempio specifico:

>>> 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)] 

Oppure, se si desidera realmente le liste:

>>> map(list, zip(*[(1, 2), (3, 4), (5, 6)])) 
[[1, 3, 5], [2, 4, 6]] 
5

Usa:

a = [(1,2),(3,4),(5,6),]  
b = zip(*a) 
>>> [(1, 3, 5), (2, 4, 6)] 
0

Aggiungendo a Claudiu e di risposta è Claudiu e poiché mappa deve essere importati da itertools in Python 3, è possibile utilizzare anche una lista di comprensione come:

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

Nonostante *zip sia più Pythonic, il seguente codice ha prestazioni molto migliori:

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

Inoltre, quando l'elenco originale zs è vuoto, verrà generato il numero *zip, ma questo codice può gestirlo correttamente.

Ho appena eseguito un esperimento veloce, e qui è il risultato:

Using *zip:  1.54701614s 
Using append: 0.52687597s 

L'esecuzione più volte, append è 3x - 4 volte più veloce zip! Lo script di test è qui:

#!/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)) 

mio Python Versione:

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 va per le prestazioni nella sua risposta e opta per list.append(), ma non sono ottimali.

Aggiunta list comprehension, ho finito con il seguente:

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 __name__ == '__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)}') 

Questo ha dato il risultato:

zip:   122.11585397789766 
append:   356.44876132614047 
list comp:  144.637765085659 

Quindi, se siete dopo la prestazione, probabilmente si dovrebbe usare zip() sebbene list comprehension sono non troppo indietro. Le prestazioni di append in realtà sono piuttosto scarse in confronto.