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])