2017-08-05 54 views
3

提取2D陣列說我有其中包含16個元素的列表:Python化的方式從列表中

lst=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'] 

此列表代表一個4×4陣列,其中所有元素已投入一維列表。在它的陣列形成它具有以下形式:

'A', 'B', 'C', 'D' 
'E', 'F', 'G', 'H' 
'I', 'J', 'K', 'L' 
'M', 'N', 'O', 'P' 

我想從這個1D列表作爲其總是開始於所述第一元件的另一1D列表中提取的子矩陣。

例如從LST中提取2×2矩陣:

'A', 'B', 'E', 'F' 

或者從LST提取的3×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的方法,因爲我不認爲這種方法將矩陣大小縮放。

回答

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()被追加到輸出。


如果你想避免整個列表轉換爲一個數組,也許是因爲元素的數量太大,要提取的窗口相對較小,我們就可以生成與塊的有效索引從NumPy broadcasting一些幫助。然後,將其作爲最終輸出索引到輸入列表中作爲列表。因此,我們最終會像這樣的東西 -

idx = (np.arange(size)[:,None]*4 + np.arange(size)).ravel() 
out = [lst[i] for i in idx] 
+0

我接受了這個取前三個項目每4項回答,因爲這是第一次,也是初步測試中最快的。謝謝,並感謝其他用戶的幫助。 – Yeti

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

這樣做沒有numpy並考慮矩陣變大時,我會使用迭代器遍歷列表,因此在提取過程中不會創建額外的列表。利用islice來獲取所需的物品,它會將每個切片操作所需的物品剔除。在提取3×3矩陣的情況下,第一片將從索引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))))