鉴于以下列表包含一些重复和一些独特的词典,首先删除唯一词典的最佳方法是什么,然后将重复的词典减少为单个实例?我得说我最近刚开始进入Python,但它使这个项目所以更容易。我对这类问题感到有点难过。
所以我的列表看起来像这样:
[{ 'file': u'/file.txt',
'line': u'line 666',
'rule': u'A DUPLICATE RULE'}
{ 'file': u'/file.txt',
'line': u'line 666',
'rule': u'A DUPLICATE RULE'}
{ 'file': u'/uniquefile.txt',
'line': u'line 999',
'rule': u'A UNIQUE RULE'}]
我想要的是最后,列表应该如下:
[{ 'file': u'/file.txt',
'line': u'line 666',
'rule': u'A DUPLICATE RULE'}]
答案 0 :(得分:4)
一个想法是对数据进行排序。假设inputdata
是您上面的列表:
from itertools import groupby
from operator import itemgetter
inputdata.sort(key=itemgetter(*inputdata[0])) # ensures order
print [k for k, g in groupby(inputdata) if len(list(g)) > 1]
打印:
[{'line': u'line 666', 'file': u'/file.txt', 'rule': u'A DUPLICATE RULE'}]
答案 1 :(得分:2)
如果每个项目的字段相同,我总是喜欢使用对象而不是dicts。
所以,我定义了一个类:
class rule(object):
def __init__(self, file, line, rule):
self.file = file
self.line = line
self.rule = rule
#Not a "magic" method, just a helper for all the methods below :)
def _tuple_(self):
return (self.file, self.line, self.rule)
def __eq__(self, other):
return cmp(self, other) == 0
def __cmp__(self, other):
return cmp(self._tuple_(), rule._tuple_(other))
def __hash__(self):
return hash(self._tuple_())
def __repr__(self):
return repr(self._tuple_())
现在,创建这些对象的列表并对其进行排序。 ruledict_list
可以是您问题中的示例数据。
rules = [rule(**r) for r in ruledict_list]
rules.sort()
循环遍历(已排序)列表,随时删除唯一对象。最后,创建一个集合,以删除重复项。循环也将删除每个重复对象中的一个,但这并不重要。
pos = 0
while(pos < len(rules)):
while pos < len(rules)-1 and rules[pos] == rules[pos+1]:
print "Skipping rule %s" % rules[pos]
pos+=1
rules.pop(pos)
rule_set = set(rules)
答案 2 :(得分:1)
我会创建另一个字典,使用现有字典作为键,并将出现次数作为值。 (Python不允许将字典用作开箱即用的字典键,但在this answer中有几种方法可以实现这一点。)然后,只需迭代它并选择键即可其中值大于1。
当然,使用字典作为键依赖于其内容不会随时间变化 - 至少在您需要使用结果字典时。 (这就是Python本身不支持它的原因。)
答案 3 :(得分:1)
另一种方法是根据冻结的项目集为每个dict数据创建一个计数器:
from operator import itemgetter
from collections import defaultdict
counter = defaultdict(int)
for d in inputdata:
counter[frozenset(d.iteritems())] += 1
result = [dict(item) for item, count in counter.iteritems() if count > 1]
print result
我认为这是迄今为止最好的答案,因为它很容易理解并且能够线性地工作。
答案 4 :(得分:1)
>>> import itertools
>>> list(a[0] for a in itertools.groupby(sorted(data)) if len(list(a[1])) > 1)
[{'file': u'/file.txt', 'line': u'line 666', 'rule': u'A DUPLICATE RULE'}]
检查这个可能比len(list(a [1]))更优化。
编辑:我添加了对sorted的调用。
答案 5 :(得分:1)
这个答案是基于Steven Huwig的回答。它与他类似,但我在列表中使用sorted()
,以便groupby()
正常工作。
另外,因为他说“检查这个可能比len(list(a [1]))更好的方式。”,我决定用其他方法来检查非唯一项目。我尝试在迭代器上调用.next()
方法两次,而不是强制整个列表。如果它工作两次,迭代器中至少有两个项目,我们就完成了它;如果我们在第一次或第二次调用StopIteration
时得到.next()
异常,则迭代器中只有零个或一个项。 (实际上,因为我们从itertools.groupby
得到了这个迭代器,我们知道它至少会有一个项目。)
此外,我没有使用像a[0]
和a[1]
这样的显式元组索引,而是使用了元组解包,因为这就是酷孩子们最近所做的事情。
最后,我不是使用生成器表达式来计算列表,而是使用list()
强制它扩展到列表中,我只是使用列表推导。
data = [
{
'file': u'/file.txt',
'line': u'line 666',
'rule': u'A DUPLICATE RULE'
},
{ 'file': u'/uniquefile.txt',
'line': u'line 999',
'rule': u'A UNIQUE RULE'
},
{ 'file': u'/file.txt',
'line': u'line 666',
'rule': u'A DUPLICATE RULE'
},
]
from itertools import groupby
def notunique(itr):
try:
itr.next()
itr.next()
return True
except StopIteration:
return False
def unique_list(lst):
return [key for key, itr in groupby(sorted(lst)) if notunique(itr)]
print(unique_list(data))
答案 6 :(得分:0)
另一个选择是创建自己的数据结构而不是使用dict。如果您这样做,则可以覆盖__cmp__,__eq__和__hash__。这将使您能够在其所有荣耀中使用“set”数据类型。
这是一个可能的实现,虽然我没有对我提供的哈希例程的质量做出承诺:
class Thing(object):
def __init__(self, file, line, rule):
self.file = file
self.line = line
self.rule = rule
def __cmp__(self, other):
result = cmp(self.file, other.file)
if result == 0:
result = cmp(self.line, other.line)
if result == 0:
result = cmp(self.rule, other.rule)
return result
def __eq__(self, other):
return cmp(self, other) == 0
def __hash__(self):
return hash(self.file) * hash(self.line) * hash(self.rule)
def __str__(self):
return ', '.join([self.file, self.line, self.rule])
things = [ Thing(u'/file.txt', u'line 666', u'A DUPLICATE RULE'),
Thing(u'/file.txt', u'line 666', u'A DUPLICATE RULE'),
Thing(u'/uniquefile.txt', u'line 999', u'A UNIQUE RULE')]
duplicate_things = set()
unique_things = set()
for t in things:
if t in unique_things:
duplicate_things.add(t)
else:
unique_things.add(t)
如果您需要返回列表,只需从结果集中构建一个:
unique_things = list(unique_things)
duplicate_things = list(duplicate_things)
要创建自己的类,需要更多代码,但如果您的程序变得复杂,可能会为您提供其他选项。
修改强>
好的,今晚我的手比我的眼睛快,但我认为这个编辑解决了@nosklo指出的问题