我有一张航空公司航班票价清单,其中'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'}
]
我尝试了很多方法,但我很难过。
答案 0 :(得分: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()
答案 1 :(得分: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
,它在幕后做同样的事情:
import collections
consolidated_tuples = collections.defaultdict(list)
每次访问不存在的key
时,defaultdict
会调用list
,将结果与key
相关联,并返回生成的空列表。
for tup in l:
consolidated_tuples[get_key(tup)].append(get_extra(tup))
您现在要做的就是重写get_key
和get_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'}}
答案 2 :(得分: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)
希望这有帮助
答案 3 :(得分: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)
我在你的例子中测试过它:
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'}]