假设我有一个包含16个元素的列表:
lst=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P']
此列表表示一个4 x 4数组,其中所有元素都已放入1D列表中。在其数组形式中,它具有以下形式:
'A', 'B', 'C', 'D'
'E', 'F', 'G', 'H'
'I', 'J', 'K', 'L'
'M', 'N', 'O', 'P'
我想从这个1D列表中提取一个子矩阵作为另一个1D列表,它总是从第一个元素开始。
e.g。从lst:
中提取2 x 2矩阵'A', 'B', 'E', 'F'
从lst:
中提取3 x 3矩阵'A', 'B', 'C', 'E', 'F', 'G', 'I', 'J', 'K'
为了达到这个目的,我使用numpy将列表调整为一个数组,提取子矩阵,然后再次展平:
import numpy as np
# The size of the matrix represented by lst
init_mat = 4
# Desired matrix size to extract
mat_size = 2
A = np.resize(lst,(init_mat,init_mat))
B = A[0:mat_size, 0:mat_size].flatten()
C = map(str,B)
这有效,但我想知道是否有更多的pythonic方法来做到这一点,因为我不认为这种方法可以很好地扩展矩阵大小。
答案 0 :(得分:3)
调用flatten()
然后调用map()
的效率低于:
B = A[:mat_size, :mat_size].reshape(-1)
C = B.tolist()
这可以避免一些副本和不必要的函数调用。
有关reshape()
vs flatten()
的更多信息,请参阅:What is the difference between flatten and ravel functions in numpy?
你也可以在没有NumPy的情况下完成。在某种程度上,这更简单。您需要使用特定的输入数据进行测试,以确定哪个更快。
[lst[i*init_mat + j] for i in range(mat_size) for j in range(mat_size)]
答案 1 :(得分:2)
一种基于阵列的方法是 -
size = 2 # or 3 or any number <= 4
np.asarray(lst).reshape(4,4)[:size,:size].ravel()
示例运行 -
In [55]: lst=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P']
In [56]: size=2
In [57]: np.asarray(lst).reshape(4,4)[:size,:size].ravel()
Out[57]:
array(['A', 'B', 'E', 'F'],
dtype='|S1')
In [58]: size=3
In [59]: np.asarray(lst).reshape(4,4)[:size,:size].ravel()
Out[59]:
array(['A', 'B', 'C', 'E', 'F', 'G', 'I', 'J', 'K'],
dtype='|S1')
如果您想要2D
数组,请跳过ravel()
部分。
如果您希望将列表作为输出,我们需要在输出中添加.tolist()
的附加步骤。
如果你想避免将整个列表转换为数组,可能是因为元素的数量太大而且要提取的窗口相对较小,我们可以通过{的一些帮助生成块的有效索引。 {3}}。然后,将其作为列表输入到最终输出的输入列表中。因此,我们最终会得到类似的东西 -
idx = (np.arange(size)[:,None]*4 + np.arange(size)).ravel()
out = [lst[i] for i in idx]
答案 2 :(得分:1)
在没有numpy的情况下执行此操作并考虑矩阵何时变大,我将使用迭代器来遍历列表,因此在提取期间不会创建额外的列表。利用islice
来获取所需的项目,它会切断每次切片操作所需的项目。在提取3x3矩阵的情况下,第一个切片将从索引0开始并在索引3之前停止,从而从迭代器中删除前三个项目。以下切片将从索引1开始,因为4 - 3 = 1,并且在4之前停止。
from itertools import chain, islice, repeat
lst=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P']
width = 4
extract = [3, 3]
slice_starts = chain([0], repeat(width - extract[0]))
slice_stops = chain([extract[0]], repeat(width))
rows = map(islice, repeat(iter(lst), extract[1]), slice_starts, slice_stops)
print(list(chain.from_iterable(rows)))
或者您可以使用compress
from itertools import chain, compress, repeat
lst=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P']
width = 4
extract = [3, 3]
selectors = repeat([i < extract[0] for i in range(width)], extract[1])
print(list(compress(lst, chain.from_iterable(selectors))))