2014-08-28 3 views
1

튜플이다 OrderedDict에서 키 수를 가져옵니다 :키가 나는 이와 같은 사전을했습니다

my_dict=collections.OrderedDict([((123, 1), 'qwe'), ((232, 1), 'asd'), ((234, 2), 'zxc'), ((6745, 2), 'aaa'), ((456, 3), 'bbb')]) 

튜플의 조합은 항상 고유 나는 삽입의 순서를 유지하고자하는, 따라서 OrderedDict. 나는 딕트 (Dict)의 ~ 10K 개 항목을 잘 처리했다. 어떻게 튜플의 두 번째 요소의 수를 제공하는 카운터를 효율적으로 유지 관리 할 수 ​​있습니까? 기본적으로 키에 항목을 추가/삭제할 때마다 카운트를 알 필요가 있습니다. 지금은 my_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 함수를 재정의하는 방법으로, 작업을 할 때마다 계수를 더하거나 뺍니다.

+0

'인스턴스를 기본 속성으로 사용합니다. –

+1

첫 번째 줄은 아무 효과가 없습니다. 'my_dict'는 두 번째 줄의 일반적인'dict'에 할당됩니다. – jfs

+0

@ J.F.Sebastian 당신 말이 맞아요. 나는 생각하지 않았다. 나의 예를 수정했다. –

답변

3

CounterOrderedDict으로 제대로 작동하려면 일부 서브 클래 싱이 필요할 것입니다.

import collections 

class CountedOrderedDict(collections.OrderedDict): 
    def __init__(self, *args, **kwargs): 
     self.counter = collections.Counter() 
     super(CountedOrderedDict, self).__init__(*args, **kwargs) 

    def __delitem__(self, key): 
     super(CountedOrderedDict, self).__delitem__(key) 
     self.counter[key[1]] -= 1 

    def __setitem__(self, key, value): 
     if key not in self: 
      self.counter[key[1]] += 1 

     super(CountedOrderedDict, self).__setitem__(key, value) 

사용 예제 : 여기

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

여기에 작동 할 수 있습니다 뭔가 (I 만 __setitem____getitem__ 구현,하지만 당신은 더 강력한 구현을 원하는 경우 알려 주시기 한)입니다 더 일반적인 CountedOrderedDict 구현은 매개 변수로 키 기능을 사용합니다.

사용자의 요구에
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) 

, 당신과 같이 인스턴스화 것 : 당신은 아마 최고의 '구현 __setitem__`과`Counter`과`OrderedDict을 유지 사용자 정의 클래스에 의해 제공 될 것

my_dict = CountedOrderedDict(key=lambda k: k[1]) 
+0

좋은 점에 더하여 그 구문은 약간 깔끔합니다. :) –

+0

두 클래스 모두'__delitem__'은 예외를 잡아서는 안되며, 억제하지 않는 것이 좋습니다. 가장 간단한 방법은'try' /'except' 블록없이 'super' 호출과 감소를 작성하는 것입니다. 'super() .__ delitem__'에서 발생한 모든 예외는 감소가 일어나지 않게 할 것입니다! 두 번째 클래스의'__init__' 메쏘드에서, 파이썬 3에서는'* args' 다음에'key'를 키워드 이동 인수로 이동시켜 키워드 전용 인수로 만들고 싶습니다. 그런 식으로'key '가 될 필요가없는 위치 적 인수를 실제로 전달할 수 있습니다. 나는 또한'key'와는 다른 이름을 사용할 것을 제안합니다! – Blckknght

+0

좋은 제안! 지금 편집합니다. –

관련 문제