2012-02-17 129 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'}]