Как преобразовать список кортежей в несколько списков? - PullRequest
84 голосов
/ 10 ноября 2011

Предположим, у меня есть список кортежей, и я хочу преобразовать его в несколько списков.

Например, список кортежей

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

Есть ли в Python встроенная функция, которая преобразует ее в:

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

Это может быть простая программа. Но мне просто любопытно существование такой встроенной функции в Python.

Ответы [ 7 ]

126 голосов
/ 10 ноября 2011

Встроенная функция zip() почти сделает то, что вы хотите:

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

Единственное отличие состоит в том, что вы получаете кортежи вместо списков.Вы можете преобразовать их в списки, используя

map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
37 голосов
/ 10 ноября 2011

Из документов Python :

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]]
8 голосов
/ 10 ноября 2011

Использование:

a = [(1,2),(3,4),(5,6),]    
b = zip(*a)
>>> [(1, 3, 5), (2, 4, 6)]
4 голосов
/ 19 января 2018

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 на самом деле довольно плохая по сравнению.

0 голосов
/ 26 мая 2019

В дополнение к ответу Клавдия, вы можете использовать:

>>>a, b = zip(*[(1, 2), (3, 4), (5, 6)])
>>>a
[1,3,5]
>>>b
[2,4,6]
0 голосов
/ 07 ноября 2017

Несмотря на то, что *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.
0 голосов
/ 24 мая 2017

Добавляя к ответу Клавдия и Клавдия, и поскольку карту необходимо импортировать из itertools в python 3, вы также используете понимание списка, например:

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