2013-06-27 69 views
5

的名單上有看起來像分組列表中的元素的給定的時間間隔

a=[['10', 'name_1'],['50','name_2'],['40','name_3'], ..., ['80', 'name_N']] 
b=[(10,40),(40,60),(60,90),(90,100)] 

a元素的兩個列表包含了一組數據,並b定義了一些區間,我的目標是創建一個列表與b中的間隔一樣多的列表。 c中的每個列表都包含間隔中包含的所有x元素,其中x[0]包含在區間中。例如:

c=[ 
[['10', 'name_1']], 
[['50','name_2'],['40','name_3']], 
[...,['80', 'name_N']] 
] 
+0

'b'中的範圍始終是連續的? –

+0

是的,他們是,而'a'由_name_而不是元素的第一個字段排序 – fady

+0

bisect在這裏可能有一些幫助 – dansalmo

回答

1

您可以使用collections.defaultdictbisect模塊的位置:

由於範圍是連續的,因此將是更好的列表b轉換爲這樣的事情第一:

[10, 40, 60, 90, 100] 

優勢這是我們現在可以使用bisect模塊來查找列表中的項目所能容納的索引。例如,50將在40和60之間,因此bisect.bisect_right將返回2在這種情況下。不,我們可以使用這2作爲關鍵,並將其存儲爲值。這樣我們可以根據從bisect.bisect_right返回的索引對這些項目進行分組。

L_b = 2* len(b) 
L_a = len(a) 
L_b1 = len(b1) 

的總體複雜性將是:max (L_b log L_b , L_a log L_b1 )

>>> import bisect 
>>> from collections import defaultdict 
>>> b=[(10,40),(40,60),(60,90),(90,100)] 
>>> b1 = sorted(set(z for x in b for z in x)) 
>>> b1 
[10, 40, 60, 90, 100] 
>>> dic = defaultdict(list) 
for x,y in a: 
    #Now find the index where the value from the list can fit in the 
    #b1 list, bisect uses binary search so this is an O(log n) step. 
    # use this returned index as key and append the list to that key. 
    ind = bisect.bisect_right(b1,int(x)) 
    dic[ind].append([x,y]) 
...  
>>> dic.values() 
[[['10', 'name_1']], [['50', 'name_2'], ['40', 'name_3']], [['80', 'name_N']]] 

由於類型的字典沒有任何特定的順序排序的使用得到有序輸出:

>>> [dic[k] for k in sorted(dic)] 
[[['10', 'name_1']], [['50', 'name_2'], ['40', 'name_3']], [['80', 'name_N']]] 
+0

謝謝你的建議,我目前正在使用你的答案,因爲它給了我更多的靈活性,對分的使用是非常有用的。 – fady

1
c = [] 
for r in b: 
    l = [] 
    rn = range(*r) 
    for element in a: 
     if int(element[0]) in rn: 
      l.append(element) 
    c.append(l) 

如果您的間隔非常大,可以考慮使用xrange代替range。實際上,如果你的間隔甚至是中等大小,請考慮以下事項。

c = [] 
for r in b: 
    l = [] 
    for element in a: 
     if r[0] <= int(element[0]) < r[1]: 
      l.append(element) 
    c.append(l) 
+0

我發現這在時間上真的很低效,因爲我繼續檢查已經分配的元素。 – fady

0

你可以這樣做這個:

>>> a=[['10', 'name_1'],['50','name_2'],['40','name_3'], ['80', 'name_N']] 
>>> b=[(10,40),(40,60),(60,90),(90,100)] 
>>> c=[] 
>>> for t in b: 
... f=list(filter(lambda l: t[0]<=int(l[0])<t[1],a)) 
... if f: c.append(f) 
... 
>>> c 
[[['10', 'name_1']], [['50', 'name_2'], ['40', 'name_3']], [['80', 'name_N']]] 
+0

'list()'似乎不需要。 – dansalmo

+0

對於Python 2,你是對的。對於解釋器中的Python 3,它或者你只是得到'[<0x1084a5710>的過濾對象,0x1084a5750>的過濾對象,...]',並且看不到結果... – dawg

0

或者你可以這樣做:

>>> a=[['10', 'name_1'],['50','name_2'],['40','name_3'], ['80', 'name_N']] 
>>> b=[(10,40),(40,60),(60,90),(90,100)] 
>>> filter(None, [filter(lambda l: t[0]<=int(l[0])<t[1], a) for t in b]) 
[[['10', 'name_1']], [['50', 'name_2'], ['40', 'name_3']], [['80', 'name_N']]] 
相關問題