Транспонировать список списков


242

Давайте принимать:

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Результат, который я ищу,

r = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

и нет

r = [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

Очень признателен

Ответы:


337

Как насчет

map(list, zip(*l))
--> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Для Python 3.x пользователи могут использовать

list(map(list, zip(*l)))

Объяснение:

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

  1. Подпись zip : zip(*iterables)это означает, zipчто ожидается произвольное количество аргументов, каждый из которых должен быть итеративным. Например zip([1, 2], [3, 4], [5, 6]).
  2. Распакованные списки аргументов : учитывая последовательность аргументов args, f(*args)будет вызываться так f, чтобы каждый элемент argsбыл отдельным позиционным аргументомf .

Возвращаясь к входу из вопроса l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], zip(*l)будет эквивалентно zip([1, 2, 3], [4, 5, 6], [7, 8, 9]). Остальное просто убедитесь, что результатом является список списков, а не список кортежей.


67
Осторожно: если lразмер не является равномерным (скажем, некоторые строки короче других), zipон не компенсирует это и вместо этого отсекает строки из выходных данных. Так l=[[1,2],[3,4],[5]]дает тебе [[1,3,5]].
Badp

29
itertoolsФункция zip_longest()работает с неровными списками. Смотри ДОКУМЕНТЫ
Орегано

13
Объяснение в ответе было бы неплохо :)
Борис Чурзин

7
Я думаю, что даже list(zip(*l))работает правильно в Python 3.
Стефано

3
@ Stefano Это работает (как zip(*l)в Python 2), но вы получаете список кортежей, а не список списков. Конечно, list(list(it))всегда одно и то же list(it).
Алексей Шпилкин

62

Один из способов сделать это с помощью транспонирования NumPy. Для списка:

>>> import numpy as np
>>> np.array(a).T.tolist()
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Или другой без почтового индекса:

>>> map(list,map(None,*a))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

8
Люблю свою вторую - я не понимал map, что смогу это сделать Вот небольшое уточнение , которое не требует 2 вызова, хотя:map(lambda *a: list(a), *l)
Ли D

7
Разве это не должно быть лучшим ответом, поскольку он заботится о неравных списках?
Леон

15
map(None, ...)не похоже на работу для Py3. Генератор создается , но next()сразу же выдает ошибку: TypeError: 'NoneType' object is not callable.
Безумный физик

57

Эквивалентно решению Йены:

>>> l=[[1,2,3],[4,5,6],[7,8,9]]
>>> [list(i) for i in zip(*l)]
... [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

12
Поскольку постижение списка теперь предпочтительнее map(), это решение является наиболее подходящим для духа Python ...
perror

26

просто для удовольствия, действительные прямоугольники и предполагая, что m [0] существует

>>> m = [[1,2,3],[4,5,6],[7,8,9]]
>>> [[row[i] for row in m] for i in range(len(m[0]))]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

это то, что я искал и не мог разобраться. Тем не менее решение @ jena очень короткое
titus

3
Да, понадобилось несколько шин, чтобы понять это правильно. Хорошо, много попыток.
Матч

9
Все еще не совсем правильно - это работает, только когда размеры квадратные! Оно должно быть: [[j[i] for j in l] for i in range(len(l[0]))]. Конечно, вы должны быть уверены, что список lне пуст.
Ли Д

@LeeD до сих пор не работает для меня на примере Джены l = [[1,2], [3,4], [5]]
варенье

3
@hobs Это был пример Бадпа, отвечающий Джене. Тем не менее, я не уверен, что это имеет смысл для меня. IMO, транспозиция подразумевает прямоугольную матрицу - когда она представлена ​​в виде списка списков, это означает, что все внутренние списки должны быть одинаковой длины. Какой результат вы бы хотели использовать в качестве «транспонирования» этого примера?
Ли Д

22

Методы 1 и 2 работают в Python 2 или 3, и они работают на рваных, прямоугольных 2D-списками. Это означает, что внутренние списки не должны иметь одинаковую длину (рваные) или внешние списки (прямоугольные). Другие методы, ну, это сложно.

установка

import itertools
import six

list_list = [[1,2,3], [4,5,6, 6.1, 6.2, 6.3], [7,8,9]]

способ 1 - map(),zip_longest()

>>> list(map(list, six.moves.zip_longest(*list_list, fillvalue='-')))
[[1, 4, 7], [2, 5, 8], [3, 6, 9], ['-', 6.1, '-'], ['-', 6.2, '-'], ['-', 6.3, '-']]

six.moves.zip_longest() становится

По умолчанию fillvalue есть None. Благодаря ответу @ jena , где map()происходит изменение внутренних кортежей в списки. Здесь он превращает итераторы в списки. Благодаря комментариям @ Oregano и @ badp .

В Python 3 передайте результат, list()чтобы получить тот же 2D-список, что и в методе 2.


метод 2 - понимание списка, zip_longest()

>>> [list(row) for row in six.moves.zip_longest(*list_list, fillvalue='-')]
[[1, 4, 7], [2, 5, 8], [3, 6, 9], ['-', 6.1, '-'], ['-', 6.2, '-'], ['-', 6.3, '-']]

@ InspectorG4dget альтернатива .


Метод 3 - map()из map()- сломан в Python 3.6

>>> map(list, map(None, *list_list))
[[1, 4, 7], [2, 5, 8], [3, 6, 9], [None, 6.1, None], [None, 6.2, None], [None, 6.3, None]]

Эта необычайно компактная вторая альтернатива @SiggyF работает с рваными 2D-списками, в отличие от его первого кода, который использует numpy для транспонирования и прохождения через рваные списки. Но None не должно быть значением заполнения. (Нет, None, передаваемый внутренней карте (), не является значением заполнения. Это означает, что нет функции для обработки каждого столбца. Столбцы просто передаются во внешнюю карту (), которая преобразует их из кортежей в списки.

Где-то в Python 3 map()перестали мириться со всем этим злоупотреблением: первым параметром не может быть None, а рваные итераторы просто усекаются до самых коротких. Другие методы все еще работают, потому что это относится только к внутренней карте ().


Метод 4 - map()из map()вновь

>>> list(map(list, map(lambda *args: args, *list_list)))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]   // Python 2.7
[[1, 4, 7], [2, 5, 8], [3, 6, 9], [None, 6.1, None], [None, 6.2, None], [None, 6.3, None]] // 3.6+

Увы, рваные строки НЕ становятся рваными столбцами в Python 3, они просто усекаются. Бу Ху прогресс.


7

Три варианта на выбор:

1. Карта с Zip

solution1 = map(list, zip(*l))

2. Понимание списка

solution2 = [list(i) for i in zip(*l)]

3. Для добавления петли

solution3 = []
for i in zip(*l):
    solution3.append((list(i)))

И для просмотра результатов:

print(*solution1)
print(*solution2)
print(*solution3)

# [1, 4, 7], [2, 5, 8], [3, 6, 9]

0

Возможно, не самое элегантное решение, но вот решение, использующее вложенные циклы while:

def transpose(lst):
    newlist = []
    i = 0
    while i < len(lst):
        j = 0
        colvec = []
        while j < len(lst):
            colvec.append(lst[j][i])
            j = j + 1
        newlist.append(colvec)
        i = i + 1
    return newlist


0

more_itertools.unzip() легко читается, и это также работает с генераторами.

import more_itertools
l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
r = more_itertools.unzip(l) # a tuple of generators.
r = list(map(list, r))      # a list of lists

или эквивалентно

import more_itertools
l = more_itertools.chunked(range(1,10), 3)
r = more_itertools.unzip(l) # a tuple of generators.
r = list(map(list, r))      # a list of lists

-1

Вот решение для транспонирования списка списков, который не обязательно квадратный:

maxCol = len(l[0])
for row in l:
    rowLength = len(row)
    if rowLength > maxCol:
        maxCol = rowLength
lTrans = []
for colIndex in range(maxCol):
    lTrans.append([])
    for row in l:
        if colIndex < len(row):
            lTrans[colIndex].append(row[colIndex])

-2
    #Import functions from library
    from numpy import size, array
    #Transpose a 2D list
    def transpose_list_2d(list_in_mat):
        list_out_mat = []
        array_in_mat = array(list_in_mat)
        array_out_mat = array_in_mat.T
        nb_lines = size(array_out_mat, 0)
        for i_line_out in range(0, nb_lines):
            array_out_line = array_out_mat[i_line_out]
            list_out_line = list(array_out_line)
            list_out_mat.append(list_out_line)
        return list_out_mat
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.