2013-02-27 75 views
2

我經常發現自己處於一個有對象列表和相關參數列表的情況:param1,param2,param3等。我想獲得具有滿足一些條件的參數。 僞代碼將是:Python:獲取列表的子集避免列表理解

subset = object if param1>10 and 5<param2-param3<6 and param4==1 

我知道該怎麼做,使用列表解析,但它得到相當難看,而且很難被別人閱讀。有替代品嗎? 例如,由兩名添加列表兩個元素,痛苦的:

list1=[1,2,3,4] 
list2=[10,10,10,10] 

[item[0]+item[1] for item in zip(list1,list2)] 
>>> [11, 12, 13, 14] 

看起來瞬間更清晰的使用與NumPy數組而不是列表解析:

import numpy 
list1=numpy.array([1,2,3,4]) 
list2=numpy.array([10,10,10,10]) 

list1 + list2 
>>> array([11, 12, 13, 14]) 

和清晰度增益獲得時更大你開始在兩個以上的列表上做一些非平凡的操作。

返回我的對象​​列表中選擇只有一些行的最初的問題:

subset = [item[0] for item in zip(object,param1,param2,param3,param4) if item[1]>10 and item[2]-item[3]>5 and item[2]-item[3]<6 and item[4]==1] 

或:

subset = [obj for obj,p1,p2,p3,p4 in zip(object,param1,param2,param3,param4) if p1>10 and p2-p3>5 and p2-p3<6 and p4==1] 

執行正是我想要的,但我沒有找到很優雅。更不用說非pythoneers快速開始告訴你「SuperMongo使它更容易」或「你希望我放棄IDL這個!」。

您是否知道爲此特定任務提供更好語法的替代解決方案? NumPy數組可以再次幫助簡化語法嗎?

回答

0

numpy的數組版本:

subset = objects[(param1>10) & (param2-param3>5) & (param2-param3<6) & (param4==1)] 

但在[]每個操作會創建一個臨時數組,如果數組的大小很大,可能需要進行一些優化。

+0

我認爲這正是我一直在尋找的! 獎勵:現在我想到了一種方法來返回對象的位置而不是對象本身。 index_of_subset = numpy。array(range(len(object)))[(param1> 10)&(param2-param3> 5)&(param2-param3 <6)&(param4 == 1)] works。可能有更聰明的做法。 – user2115545 2013-02-27 14:33:12

0

你可以使用filter或者只是使用for循環。

+0

'filter'確實不會清理任何東西,因爲過濾的條件與要過濾的值無關,所以您仍然必須將它們全部壓縮。 – 2013-02-27 14:18:28

2

我想如果你縮進正確你的第二個例子可以進行相當的可讀性:

[obj for obj, p1, p2, p3, p4 in zip(object, param1, param2, param3, param4) 
if p1 > 10 
and p2 - p3 > 5 
and p2 - p3 < 6 
and p4 == 1] 
+0

謝謝!我知道我很少縮進(除了在表達邏輯塊時),這可以改進我的代碼的一般方面。雖然語法仍然相同。 – user2115545 2013-02-27 14:26:29

0

您可以使用map/imap結合compress

from itertools import imap, compress 

compress(obj_list, imap(lambda p1, p2, p3, p4: p1 > 10 and 5 < p2 - p3 < 6 and p4 == 1, param1_list, param2_list, param3_list, param4_list)) 

你也可以將它封裝到一個函數中,以提供一個稍微乾淨的界面。

mask_filter(filter_function, data, masks): 

    return compress(data, imap(filter_function, masks)) 

mask_validator = lambda *params: params[0] > 10 and 5 < params[1] - params[2] < 6 and params[3] == 1 
parameter_lists = (param1_list, param2_list, param3_list, param4_list) 
mask_filter(mask_validator, obj_list, *parameter_lists) 
+0

這超出了我目前的技能水平,可能並不是我目前特定需求的最佳解決方案(我傾向於僅使用一次掩碼,這就是語法越短越好的原因)。但是由於它使用了一些我不知道的函數,我會試着看看我能從中學到什麼,謝謝。 – user2115545 2013-02-27 14:39:52