튜플 목록을 여러 목록으로 변환하는 방법은 무엇입니까?


108

튜플 목록이 있고 여러 목록으로 변환하고 싶다고 가정합니다.

예를 들어, 튜플 목록은 다음과 같습니다.

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

Python에 다음과 같이 변환하는 내장 함수가 있습니까?

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

이것은 간단한 프로그램이 될 수 있습니다. 그러나 나는 파이썬에 그러한 내장 함수가 존재하는지 궁금합니다.

답변:


162

내장 함수 zip()는 거의 원하는 작업을 수행합니다.

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

유일한 차이점은 목록 대신 튜플을 얻는다는 것입니다. 다음을 사용하여 목록으로 변환 할 수 있습니다.

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

40

로부터 파이썬 문서 :

* 연산자와 함께 zip ()을 사용하여 목록의 압축을 풀 수 있습니다.

구체적인 예 :

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

또는 정말로 목록을 원하는 경우 :

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


4

franklsf95는 그의 대답에서 성능을 발휘하고를 선택 list.append()하지만 최적이 아닙니다.

목록 이해력을 추가하면 다음과 같이 끝났습니다.

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)}')

결과는 다음과 같습니다.

zip:            122.11585397789766
append:         356.44876132614047
list comp:      144.637765085659

따라서 공연 후라면 zip()목록 이해력이 너무 뒤 떨어지지는 않지만 아마도 사용해야 합니다. 의 성능 append은 실제로 비교하면 꽤 나쁩니다.


1

*zip더 Pythonic 임에도 불구하고 다음 코드는 훨씬 더 나은 성능을 제공합니다.

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

또한 원본 목록 zs이 비어 있으면 발생 *zip하지만이 코드는 제대로 처리 할 수 ​​있습니다.

방금 간단한 실험을 실행했는데 결과는 다음과 같습니다.

Using *zip:     1.54701614s
Using append:   0.52687597s

여러 번 실행하면 ! append보다 3 배-4 배 빠릅니다 zip. 테스트 스크립트는 다음과 같습니다.

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

내 Python 버전 :

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.

1

Claudiu의 답변 외에도 다음을 사용할 수 있습니다.

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

@Peyman mohseni kiasari에 따라 편집 됨


1
아니! 당신 줄 것이다 (1, 3, 5)(2, 4, 6)하지를 나열합니다. 당신은 사용해야합니다map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
Peyman

0

Claudiu와 Claudiu의 답변에 추가하고 맵을 파이썬 3의 itertools에서 가져와야하므로 다음과 같은 목록 이해도 사용합니다.

[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.