รายการโยกย้าย


241

มาดูกัน:

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

ชื่นชมมาก

คำตอบ:


336

เกี่ยวกับ

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เช่นว่าองค์ประกอบในแต่ละคืออาร์กิวเมนต์ที่แยกต่างหากจากตำแหน่งargsf

กลับมาที่การป้อนข้อมูลจากคำถาม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()การทำงานที่มีรายการที่ไม่สม่ำเสมอ ดูDOCS
ออริกาโน

13
คำอธิบายในคำตอบจะดี :)
บอริส Churzin

7
ฉันคิดว่าแม้list(zip(*l))ทำงานได้อย่างถูกต้องใน Python 3
Stefano

3
@Stefano ใช้งานได้ (เหมือนzip(*l)ใน Python 2) แต่คุณจะได้รับรายชื่อของ tuples ไม่ใช่รายการของรายการ แน่นอนอยู่เสมอเป็นสิ่งเดียวกับlist(list(it)) list(it)
Alex Shpilkin

62

วิธีหนึ่งที่จะทำได้คือใช้ NumPy transpose สำหรับรายการ a:

>>> 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)
Lee D

7
นี่ไม่ควรเป็นคำตอบที่ดีกว่าเพราะจะดูแลรายการที่ไม่สม่ำเสมอ
Leon

15
map(None, ...)ดูเหมือนจะไม่ได้ผลสำหรับ Py3 เครื่องกำเนิดถูกสร้างขึ้น แต่next()ทำให้เกิดข้อผิดพลาดทันที: TypeError: 'NoneType' object is not callable.
นักฟิสิกส์บ้า

57

เท่ากับโซลูชันของ Jena:

>>> 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()แก้ปัญหานี้เป็นอย่างใดอย่างหนึ่งซึ่งเป็นส่วนใหญ่ในจิตวิญญาณของงูหลาม ...
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]]

นี่คือสิ่งที่ฉันกำลังมองหาและไม่สามารถไปรอบ ๆ โซลูชั่นของ Still @ jena นั้นสั้นมาก
ตัส

3
ใช่มันต้องใช้ยางสองสามล้อเพื่อให้ถูกต้อง โอเคหลาย ๆ ครั้ง
matchew

9
ยังไม่ถูกต้องนัก - สิ่งนี้เกิดขึ้นกับการทำงานเมื่อขนาดเป็นรูปสี่เหลี่ยมเท่านั้น! มันควรจะเป็น: [[j[i] for j in l] for i in range(len(l[0]))]. แน่นอนคุณต้องแน่ใจว่ารายการlนั้นไม่ว่างเปล่า
Lee D

@LeeD ยังไม่ทำงานกับฉันในตัวอย่างของ jena l = [[1,2], [3,4], [5]]
hobs

3
@hobs นั่นเป็นตัวอย่างของ badp ตอบ jena อย่างไรก็ตามฉันไม่แน่ใจว่ามันสมเหตุสมผลสำหรับฉัน IMO การขนย้ายหมายถึงเมทริกซ์สี่เหลี่ยม - เมื่อแสดงเป็นรายการรายการนั่นหมายความว่ารายการภายในทั้งหมดจะต้องมีความยาวเท่ากัน ผลลัพธ์ใดที่คุณต้องการให้เป็น "การเปลี่ยนแปลง" ของตัวอย่างนี้
Lee D

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()เปลี่ยนทูเปิลภายในเป็นรายการ ที่นี่จะเปลี่ยน iterators เป็นรายการ ขอขอบคุณที่ @ @ และ 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 เพื่อโอนย้ายและส่งผ่านรายการที่ขาด แต่ไม่มีต้องเป็นค่าการเติม (ไม่, ไม่มีส่งผ่านไปยังแผนที่ด้านใน () ไม่ใช่ค่าการเติมซึ่งหมายความว่าไม่มีฟังก์ชั่นในการประมวลผลแต่ละคอลัมน์คอลัมน์เพิ่งผ่านไปยังแผนที่ด้านนอก () ซึ่งแปลงพวกมันจาก tuples เป็นรายการ

อยู่ที่ไหนสักแห่งใน 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 พวกมันจะถูกตัดทอน Boo Hoo คืบหน้าไป


7

สามตัวเลือกให้เลือก:

1. แผนที่พร้อมรหัสไปรษณีย์

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

อาจไม่ใช่โซลูชันที่หรูหราที่สุด แต่นี่เป็นวิธีแก้ปัญหาโดยใช้ซ้อนในขณะที่ลูป:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.