2013-10-12 51 views
3

我有一個對象列表。每個對象都是唯一的實例,由名稱和值的任意組合組成。我想將具有重複名稱的對象組合到同一個類的新實例中,其值是所有重複值的列表。這是我非常不Python的方法:在列表中組合重複對象是否有更多的pythonic方法?

def normalise_repeatable_options(options): 
    flat = {} 
    for o in options: 
     if isinstance(o, Option): 
      flat.setdefault(o.long, []).append(o) 

    # Ensure options stay in the order they were prescribed. 
    parsed = [] 
    for o in options: 
     if isinstance(o, Option): 
      dups = flat.get(o.long) 
      if dups: 
       parsed.append(Option.combine(*tuple(dups))) 
       del flat[o.long] 
     else: 
      parsed.append(o) 

    return parsed 

更新:輸入和預期輸出功能

input = [ 
    Option('-f', '--filter', 1, 'merge file'), 
    Option('-f', '--filter', 1, 'merge anotherfile'), 
    Argument(None, 'a'), 
    Argument(None, 'b'), 
    Argument(None, 'c') 
] 

output = [ 
    Option('-f', '--filter', 1, ['merge file', 'merge anotherfile']), 
    Argument(None, 'a'), 
    Argument(None, 'b'), 
    Argument(None, 'c') 
] 

我也包括了Object.combine類方法,以防萬一你想知道是什麼,做:

@classmethod 
def combine(class_, *opts): 
    t = opts[0] 
    if len(opts) == 1: return t 
    return class_(t.short, t.long, t.argcount, [o.value for o in opts]) 
+2

可以提供樣品輸入/輸出? –

+0

哪一個'option'輸入是'o.long'? – aIKid

+0

長選項'--filter'。 – Craig

回答

1

沒有能夠測試,約約這樣的事情?

def normalise_repeatable_options(options): 
    parsed = [] 
    flat = defaultdict(list) 

    for o in options: 
     if isinstance(o, Option): 
      # For the first instance of this object, add a placemarker 
      if o.long not in flat: 
       parsed.append(o.long) 

      flat[o.long].append(o) 
     else: 
      parsed.append(o) 

    return [Option.combine(*tuple(flat[o])) if isinstance(o, str) else o for o in parsed] 

這樣,你建立你的parsed名單,離開了Option對象地點標記將被替換。我假設您的輸入列表中沒有任何對象的類型爲str

+0

在'return'語句中,定義了哪個「o」? – Craig

+0

@Craig對不起,更新。 –

+0

做了一個小改動。從@hughbrown捏出defaultdict的想法 – Craig

0

嘗試列表理解:)

不知道這是否適用於您的情況,因爲我基於一個代碼到另一個代碼的簡單映射來修改代碼。

通過檢查isinstance得到單位,所以您不必再次檢查它。

有可能在這個代碼的小錯誤:

def normalise_repeatable_options(options): 
    flat = {} 
    parsed = [] 
    [flat.setdefault(o.long, []).append(o) if isinstance(o, Option) 
    else parsed.append(o) for o in options] 

    [parsed.append(Option.combine(*tuple(lst))) if len(lst) > 1 
    else parsed.append(lst) for lst in flat.values()] 

    return parsed 
+0

*'combine',而不是'combined'。 – aIKid

+0

@alKid謝謝:) – Mai

+0

如果迭代'flat.values()',是否不會根據它的所有者的散列'long'屬性對值進行重新排序? – Craig

1

你可以從這裏開始:

from collections import defaultdict 

def normalise_repeatable_options(options): 
    actual_options = [o for o in options if isinstance(o, Option)] 
    non_options = [o for o in options if not isinstance(o, Option)] 

    flat = defaultdict(list) 
    for o in actual_options: 
     flat[o.long].append(o) 

    parsed = (
     # Make list of the non-options plus ... 
     non_options + 

     # a flattened lists of Options plus ... 
     [Option.combine(*tuple(dups)) for dup in flat.values() if len(dup) > 1] + 

     # a list of Options 
     [value[0] for value in flat.values() if len(value) == 1] 
    ) 
    return parsed 
+0

我喜歡使用'defaultdict(list)'。我已經注意到了這一點。 – Craig

相關問題