2014-06-12 60 views
1

我需要根據鍵是否大於或小於給定值將浮點列表或不同長度的(命名)元組列表分組。擴展分組代碼以處理更通用的輸入

例如,給定的2小於1的權力的列表,和截斷的列表:

twos = [2**(-(i+1)) for i in range(0,10)] 
cutoffs = [0.5, 0.125, 0.03125] 

然後起作用

split_into_groups(twos, cutoffs) 

應返回

[[0.5], [0.25, 0.125], [0.0625, 0.03125], [0.015625, 0.0078125, 0.00390625, 0.001953125, 0.0009765625]] 

I」已經實現了這樣的功能:

def split_by_prob(items, cutoff, groups, key=None): 
    for k,g in groupby(enumerate(items), lambda (j,x): x<cutoff): 
     groups.append((map(itemgetter(1),g))) 
    return groups 

def split_into_groups(items, cutoffs, key=None): 
    groups = items 
    final = [] 
    for i in cutoffs: 
     groups = split_by_prob(groups,i,[],key) 
     if len(groups) > 1: 
      final.append(groups[0]) 
      groups = groups.pop() 
     else: 
      final.append(groups[0]) 
      return final 
    final.append(groups) 
    return final 

,這些目前通過測試的是:

>>> split_by_prob(twos, 0.5, []) 
[[0.5], [0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125, 0.00390625, 0.001953125, 0.0009765625]] 

>>> split_into_groups(twos, cutoffs) 
[[0.5], [0.25, 0.125], [0.0625, 0.03125], [0.015625, 0.0078125, 0.00390625, 0.001953125, 0.0009765625]] 
>>> split_into_groups(twos, cutoffs_p10) 
[[0.5, 0.25, 0.125], [0.0625, 0.03125, 0.015625], [0.0078125, 0.00390625, 0.001953125], [0.0009765625]] 

cutoffs_p10 = [10**(-(i+1)) for i in range(0,5)]

我可以直截了當地通過改變

這個延伸到形式

items = zip(range(0,10), twos) 

的元組的列表

def split_by_prob(items, cutoff, groups, key=None): 
    for k,g in groupby(enumerate(items), lambda (j,x): x<cutoff): 
     groups.append((map(itemgetter(1),g))) 
    return groups 

def split_by_prob(items, cutoff, groups, key=None): 
    for k,g in groupby(enumerate(items), lambda (j,x): x[1]<cutoff): 
     groups.append((map(itemgetter(1),g))) 
    return groups 

如何去通過添加一個關鍵擴展原始方法默認爲浮動(或者整形等),但一個可以處理的元組和namedtuples的名單?

例如像:

split_into_groups(items, cutoffs, key=items[0]) 

將返回

[[(0,0.5)], [(1,0.25), (2,0.125)], [(3,0.0625), (4,0.03125)], [(5,0.015625), (6,0.0078125), (7,0.00390625), (8,0.001953125), (9,0.0009765625)]] 

回答

1

在我的答案我認爲,在臨界值是在最後的遞增順序 - 只是爲了簡化局面。

Discriminator檢測時隙

class Discriminator(object): 
    def __init__(self, cutoffs): 
     self.cutoffs = sorted(cutoffs) 
     self.maxslot = len(cutoffs) 
    def findslot(self, num): 
     cutoffs = self.cutoffs 
     for slot, edge in enumerate(self.cutoffs): 
      if num < edge: 
       return slot 
     return self.maxslot 

grouper把物品放入槽

from collections import defaultdict 
def grouper(cutoffs, items, key=None): 
    if not key: 
     key = lambda itm: itm 
    discr = Discriminator(cutoffs) 
    result = defaultdict(list) 
    for item in items: 
     num = key(item) 
     result[discr.findslot(num)].append(item) 
    return result 

def split_into_groups(cutoffs, numbers, key=None): 
    groups = grouper(cutoffs, numbers, key) 
    slot_ids = sorted(groups.keys()) 
    return [groups[slot_id] for slot_id in slot_ids] 

約鑑別結論和grouper

擬議鑑別工作即使對於未排序的項目。

結論約key

事實上,提供key功能比較容易,比它最初看起來。

它只是一個通過參數提供的函數,所以它成爲變換函數調用來獲取值的別名,我們希望用於比較,分組等。我們不得不使用一些身份函數。

簡單的一種是

func = lambda itm: itm 

注:所有上述功能均通過測試套件進行測試(包括使用key功能的,但是我從這個答案刪除它,因爲它變得太長時間

+0

@TomKealy最後,我在你的'key'問題中包含了'key'回答。 –

+0

感謝你的回答!你能解釋一下你爲什麼選擇了你所做的路線,也許爲什麼我寫的代碼不能擴展到做我需要的東西? –

+0

@TomKealy我這樣做是因爲貧窮的原因:我喜歡我的方式,我沒有正確閱讀你真正要求的是什麼('鑰匙'部分),並開始重寫。出於實際的原因,它允許我清楚地分割找到時隙的概念,以及在分組數據中查找元素以用於決定要使用的時隙的概念。無論如何,你的代碼看起來質量很好,我喜歡它,但我懶得鑽研所有的細節。 –