Python 从OrderedDict获取密钥计数,其中密钥是元组
我有一本这样的字典:Python 从OrderedDict获取密钥计数,其中密钥是元组,python,python-2.7,counter,ordereddictionary,Python,Python 2.7,Counter,Ordereddictionary,我有一本这样的字典: my_dict=collections.OrderedDict([((123, 1), 'qwe'), ((232, 1), 'asd'), ((234, 2), 'zxc'), ((6745, 2), 'aaa'), ((456, 3), 'bbb')]) 元组的组合总是唯一的,我希望保持插入的顺序,从而保持OrderedDict。我在dict中有超过~10K个条目。如何有效地维护一个计数器来给出元组中第二个元素的计数?基本上,每当我想在密钥中添加/删除项目时,我都需要
my_dict=collections.OrderedDict([((123, 1), 'qwe'), ((232, 1), 'asd'), ((234, 2), 'zxc'), ((6745, 2), 'aaa'), ((456, 3), 'bbb')])
元组的组合总是唯一的,我希望保持插入的顺序,从而保持OrderedDict。我在dict中有超过~10K个条目。如何有效地维护一个计数器来给出元组中第二个元素的计数?基本上,每当我想在密钥中添加/删除项目时,我都需要知道计数。现在,我只是反复浏览我的dict,每次都得到计数器,但这样做似乎非常昂贵
在上面的示例中,我希望输出为:
1:2 # As in 1 occurs 2 times
2:2
3:1
现在我要做的是:
from collections import OrderedDict, Counter
my_dict = OrderedDict()
my_dict[(123,1)] = 'qwe'
my_dict[(232,1)] = 'asd'
my_dict[(234,2)] = 'zxc'
my_dict[(6745,2)] = 'aaa'
my_dict[(456,3)] = 'bbb'
cnt = []
for item in my_dict.keys():
cnt.append(item[1])
print Counter(cnt)
我不确定这是否是最好的方法,但是否有一种方法可以覆盖
=
操作符和pop
函数,这样每次我执行该操作时它都会增加或减少一个计数?获得一个计数器来很好地处理OrderedDict
可能需要一些子类化。下面是一些可能有效的方法(我只实现了\uuuu setitem\uuuuuuuu
和\uuuu getitem\uuuuuuuuu
,但是如果您想要更健壮的实现,请告诉我):
用法示例:
>>> my_dict = CountedOrderedDict({(123,1): 'sda', (232,1) : 'bfd', (234,2) : 'csd', (6745,2) : 'ds', (456,3) : 'rd'})
>>> my_dict.counter
Counter({'1': 2, '2': 2, '3': 1})
>>> del my_dict[(123,1)]
>>> my_dict.counter
Counter({'2': 2, '1': 1, '3': 1})
>>> my_dict[(150,1)] = "asdf"
>>> my_dict.counter
Counter({'1': 2, '2': 2, '3': 1})
这里有一个更通用的countedOrderdICT
实现,它将一个键函数作为参数
import collections
class CountedOrderedDict(collections.OrderedDict):
def __init__(self, key=lambda k: k, *args, **kwargs):
self.counter = collections.Counter()
self.key_transform = key
super(CountedOrderedDict, self).__init__(*args, **kwargs)
def __delitem__(self, key):
super(CountedOrderedDict, self).__delitem__(key)
self.counter[self.key_transform(key)] -= 1
def __setitem__(self, key, value):
if key not in self:
self.counter[self.key_transform(key)] += 1
super(CountedOrderedDict, self).__setitem__(key, value)
为了满足您的需要,您可以这样实例化它:
my_dict = CountedOrderedDict(key=lambda k: k[1])
您最好使用一个自定义类,该类实现了\uuuu setitem\uuuu
,并将计数器和OrderedDict
实例作为基础属性。第一行无效my_dict
被分配到第二行的普通dict
。@J.F.Sebastian你说得对。我没在想。更正了我的示例。collections.Counter(我的dict.iterkeys()中x的x[1])
将执行for循环在这两个类中所做的操作,我建议\uu delitem\uuu
应该重新释放它捕获的异常,而不是抑制它。最简单的方法可能是只编写super
调用和减量,除了
块之外,不使用任何try
/。在super()中引发的任何异常都将阻止减量发生!在第二个类的\uuuu init\uuu
方法中,在Python3中,您可能希望通过将key
移动到*args
之后,使其成为一个只包含关键字的参数。通过这种方式,您实际上可以传递位置参数,而无需将第一个参数设置为键
。我还建议使用与键不同的名称@好建议。我写了一篇详尽而难看的评论,询问同一个问题,只有一个例外。谢谢我更改了参数中键的顺序,以便在不提供键的情况下提供非关键字参数,但保留“键”作为参数的名称,因为它在其他实例中也有类似的用法(例如在排序的和max
/min
中)@Dan编译这段代码时,我在def\uuuu init\uuuu(self,*args,key=lambda k:k,**kwargs)
行中遇到了一个无效的语法错误。我不明白为什么要给出一个建议。哎呀,这就是当我编辑代码而不首先运行它时发生的情况。:)固定的。
my_dict = CountedOrderedDict(key=lambda k: k[1])