我有一个dicts列表,我希望将该列表中的每个dict与结果列表中的dict进行比较,如果它不存在则将其添加到结果列表中,如果它在那里,则更新与该dict相关联的计数器
起初我想使用Python : List of dict, if exists increment a dict value, if not append a new dict中描述的解决方案,但是我得到一个错误,其中一个dict不能用作另一个dict的键。
所以我选择的数据结构是一个列表,其中每个条目都是一个dict和一个int:
r = [[{'src': '', 'dst': '', 'cmd': ''}, 0]]
原始数据集(应与结果数据集进行比较)是一个dicts列表:
d1 = {'src': '192.168.0.1',
'dst': '192.168.0.2',
'cmd': 'cmd1'}
d2 = {'src': '192.168.0.1',
'dst': '192.168.0.2',
'cmd': 'cmd2'}
d3 = {'src': '192.168.0.2',
'dst': '192.168.0.1',
'cmd': 'cmd1'}
d4 = {'src': '192.168.0.1',
'dst': '192.168.0.2',
'cmd': 'cmd1'}
o = [d1, d2, d3, d4]
结果应为:
r = [[{'src': '192.168.0.1', 'dst': '192.168.0.2', 'cmd': 'cmd1'}, 2],
[{'src': '192.168.0.1', 'dst': '192.168.0.2', 'cmd': 'cmd2'}, 1],
[{'src': '192.168.0.2', 'dst': '192.168.0.1', 'cmd': 'cmd1'}, 1]]
完成此操作的最佳方法是什么?我有一些代码示例,但没有一个是非常好的,大多数都没有正常工作。
感谢您的任何意见!
更新
Tamås评论后的最终代码是:
from collections import namedtuple, defaultdict
DataClass = namedtuple("DataClass", "src dst cmd")
d1 = DataClass(src='192.168.0.1', dst='192.168.0.2', cmd='cmd1')
d2 = DataClass(src='192.168.0.1', dst='192.168.0.2', cmd='cmd2')
d3 = DataClass(src='192.168.0.2', dst='192.168.0.1', cmd='cmd1')
d4 = DataClass(src='192.168.0.1', dst='192.168.0.2', cmd='cmd1')
ds = d1, d2, d3, d4
r = defaultdict(int)
for d in ds:
r[d] += 1
print "list to compare"
for d in ds:
print d
print "result after merge"
for k, v in r.iteritems():
print("%s: %s" % (k, v))
答案 0 :(得分:1)
好吧,如果您的原始dicts仅包含src
,dst
和cmd
,则可以使用命名元组,它们是可清除的,因此您可以在dict中使用命名元组作为密钥。
from collections import namedtuple
DataClass = namedtuple("DataClass", "src dst cmd")
d1 = DataClass(src='192.168.0.2', dst='192.168.0.1', cmd='cmd1')
(抱歉这个愚蠢的班级名称;因为我不知道你的词汇代表什么,所以我无法想出一个更好的名字)。您甚至可以从dicts创建DataClass
个实例:
d1 = DataClass(**d1_as_dict)
此时,您的主计数循环简化为:
from collections import defaultdict, namedtuple
r = defaultdict(int)
for obj in [d1, d2, d3, d4]:
r[obj] += 1
如果出于某种原因,您仍然坚持使用Python< = 2.5,则会有一个namedtuple
替代课here。
答案 1 :(得分:1)
namedtuple
是一个很好的主意,如果适用的话。但是如果你想坚持使用dict
,那当然也是可能的,效率大大降低。例如:
def addadict(r, newd):
for i, (d, count) in enumerate(r):
if d == newd:
r[i] = [d, count+1]
break
else:
r.append([newd, 1])