Функция транспонирования / распаковки (обратная сторона zip)? - PullRequest
444 голосов
/ 21 августа 2008

У меня есть список кортежей из 2 элементов, и я хотел бы преобразовать их в 2 списка, где первый содержит первый элемент в каждом кортеже, а второй список содержит второй элемент.

Например:

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Есть ли встроенная функция, которая делает это?

Ответы [ 13 ]

0 голосов
/ 26 сентября 2018

Хотя zip(*seq) очень полезно, оно может быть неподходящим для очень длинных последовательностей, так как создаст набор значений для передачи. Например, я работал с системой координат с более чем миллионом записей найти это значительно быстрее, чтобы создавать последовательности напрямую.

Общий подход будет выглядеть примерно так:

from collections import deque
seq = ((a1, b1, …), (a2, b2, …), …)
width = len(seq[0])
output = [deque(len(seq))] * width # preallocate memory
for element in seq:
    for s, item in zip(output, element):
        s.append(item)

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

И, как уже отмечали другие, если вы делаете это с наборами данных, может иметь смысл вместо этого использовать коллекции Numpy или Pandas.

0 голосов
/ 23 августа 2018

Ни один из предыдущих ответов эффективно не обеспечивает требуемый вывод, который представляет собой набор списков , а не список наборов Для первого вы можете использовать tuple с map. Вот разница:

res1 = list(zip(*original))              # [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
res2 = tuple(map(list, zip(*original)))  # (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Кроме того, большинство предыдущих решений предполагают Python 2.7, где zip возвращает список, а не итератор.

Для Python 3.x вам понадобится передать результат в функцию, такую ​​как list или tuple, чтобы исчерпать итератор. Для итераторов с эффективным использованием памяти можно пропустить внешние вызовы list и tuple для соответствующих решений.

0 голосов
/ 30 июня 2018

Вот как вы можете переместить кортеж 2x4 в кортеж 4x2.

 >>> tuple(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])) 

результат

[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
...