假设我有以下列表
l = [ {'id':1, 's':1.0 }, {'id':3, 's': 0.6}, {'id':1, 's': 1.5} ]
我想根据'id'
值删除重复's'
值的元素
在前一个例子中,我想丢弃第一个元素,因为第一个和第三个元素都有'id'==1
,而l[0]['s'] < l[2]['s']
我希望l[0]
被丢弃。
因此我期望的输出是(我不关心输出列表中元素的顺序)
[ {'id':1, 's':1.5}, {'id':3, 's':0.6} ]
答案 0 :(得分:5)
我会使用映射来跟踪ID及其分数:
from collections import defaultdict
id_to_scores = defaultdict(list)
for entry in l:
id_to_scores[entry['id']].append(entry['s'])
output = [{'id': k, 's': max(v)} for k, v in id_to_scores.iteritems()]
如果您使用的是Python 3,请使用.items()
。
结果(由于dict
没有固定排序,订单已更改):
>>> [{'id': k, 's': max(v)} for k, v in id_to_scores.iteritems()]
[{'s': 1.5, 'id': 1}, {'s': 0.6, 'id': 3}]
这会重建词典。如果涉及其他键,则需要为每个id
存储整个字典,而不仅仅是分数:
per_id = defaultdict(list)
for entry in l:
per_id[entry['id']].append(entry)
output = [max(v, key=lambda d: d['s']) for v in per_id.itervalues()]
答案 1 :(得分:4)
使用collections.defaultdict
:
In [58]: dic=defaultdict(dict)
In [59]: for x in lis:
idx=x['id']
if dic[idx].get('s',float('-inf')) < x ['s']:
dic[idx]=x
....:
In [60]: dic.values()
Out[60]: [{'id': 1, 's': 1.5}, {'id': 3, 's': 0.6}]
使用简单的dict
:
In [71]: dic={}
In [72]: for x in lis:
idx=x['id']
if dic.get(idx, {'s': float('-inf')}) ['s'] < x['s']:
dic[idx]=x
....:
In [73]: dic.values()
Out[73]: [{'id': 1, 's': 1.5}, {'id': 3, 's': 0.6}]
答案 2 :(得分:3)
这是我的解决方案,使用来自itertools的groupby。
>>> l = [ {'id':1, 's':1.0 }, {'id':3, 's': 0.6}, {'id':1, 's': 1.5} ]
>>> from itertools import groupby
>>> key = lambda dct: dct['id']
>>> l.sort(key=key)
>>> for key, group in groupby(l, key=key):
... print max(group, key=lambda dct: dct['s'])
...
{'s': 1.5, 'id': 1}
{'s': 0.6, 'id': 3}
回复:Ashwini
我做了performance test,比较了不同的解决方案。这是结果,以图表形式:
我在这里只使用了'id'
键的10个不同值,您可以自己使用代码来查看lst
的组合如何影响结果。将id
值的数量更改为列表中项目数量的一半,使得Ashwini成为明确的胜利者,让我们其余的人陷入困境:
这是将O(n)
解决方案与O(n*log(n))
解决方案在日志日志图表中进行比较时的样子:
所以,我不太确定关于大O论证的结论是什么。
答案 3 :(得分:0)
>>> L = [ {'id':1, 's':1.0 }, {'id':3, 's': 0.6}, {'id':1, 's': 1.5} ]
>>> res = {}
>>> for d in L:
id_ = d['id']
res[id_] = max(res.get(id_, {}), d, key=lambda x: x.get('s', float('-inf')))
>>> res.values()
[{'s': 1.5, 'id': 1}, {'s': 0.6, 'id': 3}]
答案 4 :(得分:0)
>>> l2={}
>>> for y in l:
l2.setdefault(y['id'],[]).append(y['s'])
>>> l3=[{'id':k,'s':max(v)} for k,v in l2.items()]
>>> print l3
给出:
[{'id': 1, 's': 1.5}, {'id': 3, 's': 0.6}]
答案 5 :(得分:0)
按降序s
排序,因此对于每个id
,最高s
排在第一位。然后只选择第一次出现的id
。
seen = set()
output = [d for d in sorted(l, key=lambda d: d['s'], reverse=True)
if d['id'] not in seen and not seen.add(d['id'])]
您可以决定先进行排序,以避免额外的空间,但需要以触摸输入为代价。
所有这些在时间和空间复杂性方面可能都不是最佳的,但它非常优雅。