Как преобразовать список кортежей в несколько списков?
Предположим, у меня есть список кортежей, и я хочу преобразовать их в несколько списков.
Например, список кортежей
[(1,2),(3,4),(5,6),]
Есть ли встроенная функция в Python, которая преобразует ее в:
[1,3,5],[2,4,6]
Это может быть простая программа. Но мне просто интересно узнать о существовании такой встроенной функции в Python.
Ответы
Ответ 1
Встроенная функция zip()
почти сделает то, что вы хотите:
>>> zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]
Единственное различие заключается в том, что вы получаете кортежи вместо списков. Вы можете преобразовать их в списки, используя
map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
Ответ 2
В документах 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]]
Ответ 3
Использование:
a = [(1,2),(3,4),(5,6),]
b = zip(*a)
>>> [(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
на самом деле довольно плохая по сравнению.
Ответ 5
Добавляя к Claudiu и Claudiu ответ, и поскольку карта должна быть импортирована из itertools в python 3, вы также используете понимание списка, например:
[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
Ответ 6
Несмотря на то, что *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
на 3x - 4 раза быстрее, чем zip
! Тест script находится здесь:
#!/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.
Ответ 7
Помимо ответа Клаудиу, вы можете использовать:
>>>a, b = zip(*[(1, 2), (3, 4), (5, 6)])
>>>a
[1,3,5]
>>>b
[2,4,6]