2012-02-17 88 views
2

我有一個'price',一個'tickettype',表示如果票價是「單向」(而不是往返,並通過整數代碼映射到另一個旅程列表),但我收到的列表是重複的。如何迭代詞典列表併合並詞典以形成新的較短的詞典列表?

[ 
{'price' : 1800, 'oneway' : 1, 'inboundJourneys' : [], "outboundJourneys": [3], 'tickettypecode' : 'SDS'}, 
{'price' : 1800, 'oneway' : 1, 'inboundJourneys' : [9,10,11], "outboundJourneys": [], 'tickettypecode' : 'SDS'}, 
{'price' : 1800, 'oneway' : 1, 'inboundJourneys' : [14,16], "outboundJourneys": [], 'tickettypecode' : 'SDS'}, 
{'price' : '2300', 'oneway' : 1, 'inboundJourneys' : [], "outboundJourneys": [6,8,9], 'tickettypecode' : 'TAR'}, 
{'price' : 2300, 'oneway' : 1, 'inboundJourneys' : [12,13,14], "outboundJourneys": [3], 'tickettypecode' : 'TAR'}, 
{'price' : 900, 'oneway' : 1, 'inboundJourneys' : [], "outboundJourneys": [18,19,20], 'tickettypecode' : 'GED'}, 
{'price' : 900, 'oneway' : 1, 'inboundJourneys' : [14,16,17], "outboundJourneys": [], 'tickettypecode' : 'GED'}, 
{'price' : 1200, 'oneway' : 1, 'inboundJourneys' : [], "outboundJourneys": [25], 'tickettypecode' : 'ABC'}, 
{'price' : 1200, 'oneway' : 1, 'inboundJourneys' : [32], "outboundJourneys": [], 'tickettypecode' : 'ABC'} 
] 

我需要的是:

哪裏'price'等於和'tickettypecode'等於和'oneway'等於有列表中的一個字典,結束了:

[ 
{'price' : 1800, 'oneway' : 1, 'inboundJourneys' : [9,10,11,14,16], "outboundJourneys": [3], 'tickettypecode' : 'SDS'}, 
{'price' : 2300, 'oneway' : 1, 'inboundJourneys' : [12,13,14], "outboundJourneys": ['6,8,9'], 'tickettypecode' : 'TAR'}, 
{'price' : 900, 'oneway' : 1, 'inboundJourneys' : [14,16,17], "outboundJourneys": [18,19,20], 'tickettypecode' : 'GED'}, 
{'price' : 1200, 'oneway' : 1, 'inboundJourneys' : [32], "outboundJourneys": [25], 'tickettypecode' : 'ABC'} 
] 

我嘗試了很多方法,但我很難過。

+2

請發表您嘗試的代碼。你所要做的就是迭代列表,比較值併合並列表。 – 2012-02-17 17:19:32

+1

是否有意識地將'inboundJourneys'指向包含0或1個逗號分隔字符串的列表?對我來說看起來很奇怪。 – 2012-02-17 17:20:37

+0

列表中的項目順序是否重要? – 2012-02-17 17:21:59

回答

3

假設合併列表中的項目順序無關緊要,只需遍歷列表中的每個項目,然後複製它,如果您之前沒有看到它或合併字段(如果有)。

merged = {} 

for item in original: 
    key = (item['price'], item['tickettypecode'], item['oneway']) 
    if key in merged: 
     for mergekey in ['inboundJourneys','outboundJourneys']: 
      # assign extended copy rather than using list.extend() 
      merged[key][mergekey] = merged[key][mergekey] + item[mergekey] 
    else: 
     merged[key] = item.copy() 

mergedlist = merged.values() 
0

一般來說,像這樣的情況最好由字典處理。例如:

l = [(1, 2, 3), (1, 2, 8), (2, 3, 9), (5, 6, 66), 
    (3, 4, 22), (4, 5, 24), (5, 6, 55), (3, 4, 11)] 

這裏我們有一個元組列表。現在說,如果元組中的前兩個值相等,我們希望兩個元組「相等」,並且我們希望合併後面的值。我們可以使用元組作爲字典鍵;所以對於每個元組,我們都會像這樣生成一個關鍵元組。我將定義一個函數爲清晰起見,在這裏:

def get_key(tup): 
    return tup[0:2] 

這切片的元組,與前兩個值返回一個元組。對於這樣一個簡單的操作來說,一個函數看起來可能過於矯枉過正,但對於更復雜的操作,它使事情變得更加清晰。

我還會定義返回額外的數據功能:

def get_extra(tup): 
    return tup[2] 

現在,我們創建了一個詞典:

consolidated_tuples = {} 

和填充它:

for tup in l: 
    key = get_key(tup) 
    extra = get_extra(tup) 
    if key not in consolidated_tuples: 
     consolidated_tuples[key] = [extra] 
    else: 
     consolidated_tuples[key].append(extra) 

這只是檢查密鑰是否在字典中。如果不是,則它創建一個包含元組中最後一個值的列表,並將該列表分配給該鍵。如果是,則它將給定元組中的最後一個值附加到列表中(已存在)。這樣,重複項被合併;生成相同密鑰的元組導致相同的列表,然後填充各種結尾值。

您可以輕鬆擴展此方法以使用字典列表;它只是變得更復雜一點。

從這個基本的代碼,我們可以添加一些複雜性。例如,字典有一個setdefault方法,該方法嘗試訪問字典中的鍵,如果不能,則創建它,爲其分配默認值並返回該默認值。這意味着,上述if... else語句可以壓縮:

for tup in l: 
    consolidated_tuples.setdefault(get_key(tup), []).append(get_extra(tup)) 

的等效方法是使用defaultdict,它做同樣的事情如上幕後:

每次不存在key是訪問,defaultdict調用list,將結果與key相關聯,並返回結果空列表。

for tup in l: 
    consolidated_tuples[get_key(tup)].append(get_extra(tup)) 

所有你現在要做的就是改寫get_keyget_extra與上面的數據進行工作。

>>> def get_key(d): 
...  return (int(d['price']), d['oneway'], d['tickettypecode']) 
... 
>>> def get_extra(d): 
...  return (d['outboundJourneys'], d['inboundJourneys']) 
... 
>>> merged_data = collections.defaultdict(list) 
>>> for d in data: 
...  merged_data[get_key(d)].append(get_extra(d)) 

結果可以很容易地轉換爲類似於初始結構;如果你想在字典'price'等,只需添加他們在下面的步驟:

>>> for k in merged_data: 
...  ob, ib = zip(*merged_data[k]) 
...  merged_data[k] = {'outboundJourneys': [x for l in ob for x in l], 
...      'inboundJourneys': [x for l in ib for x in l]} 
... 
>>> merged_data 
defaultdict(<type 'list'>, { 
    (2300, 1, 'TAR'): 
     {'outboundJourneys': [6, 8, 9, 3], 'inboundJourneys': [12, 13, 14]}, 
    (1200, 1, 'ABC'): {'outboundJourneys': [25], 'inboundJourneys': [32]}, 
    (1800, 1, 'SDS'): 
     {'outboundJourneys': [3], 'inboundJourneys': [9, 10, 11, 14, 16]}, 
    (900, 1, 'GED'): 
     {'outboundJourneys': [18, 19, 20], 'inboundJourneys': [14, 16, 17]} 
}) 

你也可以寫一個函數,而不是簡單地將額外的數據附加到一個列表,會以更復雜的方式合併它。在這種情況下,defaultdict可能會增加一些不必要的複雜性;我們可以使用dict.get(key, default),它搜索一個鍵並返回一個默認值,如果沒有找到。全部放在一起,定製上面的數據(這裏命名flights):

def merge_dict(d1, d2, key_names): 
    merged_d = d1.copy() 
    merged_d.update(d2) 
    merged_d.update((k, d1.get(k, []) + d2.get(k, [])) for k in key_names) 
    return merged_d 

merged = {}   
for d in flights: 
    key = (int(d['price']), d['tickettypecode'], d['oneway']) 
    cd = merged.get(key, {}) 
    merged[key] = merge_dict(cd, d, ('inboundJourneys', 'outboundJourneys')) 

結果:

>>> consolidated_flights 
{(1200, 'ABC', 1): {'inboundJourneys': [32], 'price': 1200, 
    'outboundJourneys': [25], 'oneway': 1, 'tickettypecode': 'ABC'}, 
(2300, 'TAR', 1): {'inboundJourneys': [12, 13, 14], 'price': 2300, 
    'outboundJourneys': [6, 8, 9, 3], 'oneway': 1, 'tickettypecode': 'TAR'}, 
(1800, 'SDS', 1): {'inboundJourneys': [9, 10, 11, 14, 16], 'price': 1800, 
    'outboundJourneys': [3], 'oneway': 1, 'tickettypecode': 'SDS'}, 
(900, 'GED', 1): {'inboundJourneys': [14, 16, 17], 'price': 900, 
    'outboundJourneys': [18, 19, 20], 'oneway': 1, 'tickettypecode': 'GED'}} 
0

效率極其低下的解決方案,而是一個起點:

answer = [] 
for myDict in myList: 
    for d in answer: 
     if d['oneway']==myDict['oneway'] and d['price']==myDict['price'] and d['tickettype']==myDict['tickettype']: 
      break 
    else: 
     answer.append(myDict) 

希望這幫助

0

我會這樣做:

import copy 

def merge(iterable, keys, update): 
    merged = {} 
    for d in iterable: 
     merge_key = tuple(d[k] for k in keys) 
     m = merged.get(merge_key) 
     if m: 
      for u in update: 
       m[u].extend(d[u]) 
     else: 
      merged[merge_key] = copy.deepcopy(d) 

    return list(merged.values()) # list(dict_view) 

我已經測試它在你的exampe:

keys = ('price','tickettypecode','oneway') 
update = ('inboundJourneys','outboundJourneys') 
merge(l, keys, update) 

而且我得到了:

[{'inboundJourneys': [32], 
    'oneway': 1, 
    'outboundJourneys': [25], 
    'price': 1200, 
    'tickettypecode': 'ABC'}, 
{'inboundJourneys': [12, 13, 14], 
    'oneway': 1, 
    'outboundJourneys': [6, 8, 9, 3], 
    'price': 2300, 
    'tickettypecode': 'TAR'}, 
{'inboundJourneys': [9, 10, 11, 14, 16], 
    'oneway': 1, 
    'outboundJourneys': [3], 
    'price': 1800, 
    'tickettypecode': 'SDS'}, 
{'inboundJourneys': [14, 16, 17], 
    'oneway': 1, 
    'outboundJourneys': [18, 19, 20], 
    'price': 900, 
    'tickettypecode': 'GED'}]