【问题标题】:Rearranging a (list of lists) matrix using list comprehensions only仅使用列表推导重新排列(列表列表)矩阵
【发布时间】:2015-10-17 09:22:27
【问题描述】:

考虑以下 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 安装上工作(没有额外的库);
  • 必须是(类似于矩阵转置)“单线”。

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

当我不得不为此寻找解决方案时,我做了以下事情(基于我在下面我自己的 cmets 中给出的建议):

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 也注意到的那样,“公式”可以“概括”,以便将初始(列表列表)矩阵重新排列为不同的“形状"。

【问题讨论】:

  • @Clodion(征求建议)和谁可能需要或感兴趣,我知道的是:命名ir , ic 初始矩阵行和列的总数i , j初始矩阵行和列的索引r , c重新排列的索引,具有k = ic*(i-1)+j,“索引重新映射公式" 将是 r = (k-1) // ir + 1c = (k-1) % ir + 1。附言请注意,c 也可以通过这种方式重新映射:c = (j % ic if j % ic > 0 else i)
  • 所以,在这种情况下:ir=3ic=4k = 4*(i-1)+jr = (k-1) // 3 + 1c = (k-1) % 3 + 1(甚至是 c = (j % 4 if j % 4 > 0 else i))。
  • P.S.获取原始矩阵的行数和冒号可以分别使用:len(mat)len(mat[0])
  • P.P.S.显然,我在上一条评论中真正的意思是 columnsnot colons

标签: python list matrix list-comprehension


【解决方案1】:

这样的事情怎么样:

>>> 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中提供下一个元素。

进一步说明:如果需要,您甚至可以将初始矩阵重新排列为与 4 x 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]]

【讨论】:

  • OP 说:would it be possible to obtain that using only list comprehensions? 没有?
  • 我猜它的目的是他不想画出一个复杂的算法来做这件事。这就是我从中得到的 - 我知道可以制定出一种算法来完成任务但是是否有可能仅使用列表推导来获得它?
  • 另外,我用map() 做的事情可以很容易地通过列表理解来实现,但我认为map() 更适合它。
  • 哇!您的解决方案给我留下了非常积极的印象,因为您实际上可以通过这种方式使其成为一个衬里:list(zip(*[(y for x in matrix for y in x)]*3)),也是目前唯一一个满足所有要求的解决方案(我编辑了我的问题)。你能提供一个类似于转置方式的解决方案吗?看看是否可能只是一个“加号”(只是出于好奇),无论如何我也喜欢使用 zip/map。 8-)
  • 对不起,我不明白你的意思不是转置方式,你的意思是你在问题中显示的矩阵转置?如果没有,你能举个例子帮助我理解吗?
【解决方案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]]

【讨论】:

  • 请看我的问题编辑和下面的 cmets。不幸的是,如果之前没有安装 NumPy 的库包,则无法导入它……但是,您的 NumPy 解决方案将是一个不错的单线 :-)
  • P.S. :我承认到目前为止我从未使用过 NumPy,所以我想知道,那个输出是“真实的”吗?我的意思是,对齐的堆叠值并且没有逗号?
  • @danicotra:是的。这就是 numpy 默认打印结果的方式。您对数学矩阵的期望。
  • @danicotra:现在它是一个单行 btw :)
  • 哇...酷!不是吗? :-D
【解决方案3】:

以下解决方案仅使用列表推导,不使用 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:]]

【讨论】:

  • 我编辑了我的问题,提供了接受答案的要求(以及下面的一些 cmets)。请看一看。
【解决方案4】:

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

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]

这是你的问题,不是吗?

【讨论】:

  • 请看我的问题编辑和下面的 cmets,也许你会发现一些有用的建议?
  • @danicotra:是的,我读过它,但我认为它对我来说太复杂了。但它给了我想法!我已将答案编辑为只有一个理解列表。
  • 是的,我明白了,不错的“通用”解决方案 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 2014-08-12
  • 2017-09-11
相关资源
最近更新 更多