仅使用列表推导重新排列(列表列表)矩阵

时间:2015-07-27 09:00:19

标签: python list matrix list-comprehension

考虑以下3 x 4矩阵实现为Python中3个长度为4的列表的列表:

>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]

以下列表理解将重新排列矩阵转置行和列:

>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

但是假设我需要这个结果:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]

这是一个重新排列的4 x 3矩阵,以便获得原始矩阵的顺序“滚动”,每3个元素“中断”到一个新行。

我知道可以绘制一个算法来完成任务,但是是否可以仅使用列表推导来获得它?(如果是的话,怎么做?)

修改

接受的答案应符合以下要求:

  • 必须处理基本/干净的Python安装(没有其他库);
  • 必须(与矩阵换位相似)为“单线”。

第二次EDIT +接受的答案动机:

以下是我必须为此找到解决方案时所做的事情(根据我在下面的评论中提出的建议):

mat = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]

[[mat[(3*(i-1)+j -1)//4+1][(3*(i-1)+j -1)%4] for j in range(3)] for i in range(4)]

请注意,我写的解决方案是针对这种情况的,但是,正如Clodion所注意到的那样,“公式”可以“推广”,以便将初始(列表列表)矩阵重新排列为不同的“形状” ”

4 个答案:

答案 0 :(得分:3)

这样的事情怎么样:

>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>> it = (y for x in matrix for y in x)
>>> list(zip(*[it]*3))
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]

如果您想要列表清单:

>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>> it = (y for x in matrix for y in x)
>>> list(map(list, zip(*[it]*3)))
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]

说明:

  1. 首先我们创建一个生成器,它给出列表的元素(好像它被展平为一个列表 - 即1,2,3,4,5,6,...,12) - 我们将其存储在it

  2. 然后我们致电zip()给它it三次;由于生成器是相同的,它每次都在it中提供下一个元素。

  3. 进一步说明:如果需要,您甚至可以通过简单地将3更改为所需的列数,以不同的“形状”重新排列初始矩阵。 (例如,将其更改为26,您将分别获得6 x 2或2 x 6重新排列的矩阵。

    一种不使用zip的方法,只使用列表推导,但它需要两行 -

    >>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
    >>> it = (y for x in matrix for y in x)
    >>> [[next(it) for _ in range(3)] for _ in range(4)]
    [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
    

答案 1 :(得分:2)

numpy是一个选项吗?

import numpy

x = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
y = numpy.array(x).reshape((4, 3))
print y

输出:

[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]

这里至少有一个列表理解,我现在缺乏创造力,但这有点诀窍:P

print [[[z for y in x for z in y][i*3+j] for j in range(len(x))] for i in range(len(x[0]))]

输出:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]

答案 2 :(得分:2)

以下解决方案仅使用列表推导,而不使用zip:

m = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]

flat = [l2 for l1 in m for l2 in l1]
output = [[flat.pop(0), flat.pop(0), flat.pop(0)] for x in range(4)]

print(output)

输出是:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]

或者对于一个非常简单的一个班轮:

print [m[0][:3],[m[0][3]]+m[1][0:2],m[1][2:]+[m[2][0]],m[2][1:]]

答案 3 :(得分:1)

嗯,只有列表,它很粗糙(建议会受到赞赏吗?):

matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
lst = [y for row in matrix for y in row]
lst = [[lst[x+y*3] for x in range(3)] for y in range(4)]
print(lst)

结果:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]

是的!在一个列表理解中:

nr, nc = 4, 3
ic = len(matrix[0])
lst = [[matrix[(r*nc+c)//ic][(r*nc+c)%ic] for c in range(nc)] for r in range(nr)]
print(*lst, sep="\n")

结果:

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10, 11, 12]

但你也可以(nr, nc = 6, 2

[1, 2]
[3, 4]
[5, 6]
[7, 8]
[9, 10]
[11, 12]

那是你的问题,不是吗?