从列表

时间:2017-08-05 12:51:39

标签: python list numpy

假设我有一个包含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方法来做到这一点,因为我不认为这种方法可以很好地扩展矩阵大小。

3 个答案:

答案 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

从每4件商品中取出前三件商品
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))))