2013-05-05 1 views
6

Мой код в настоящее время должен считать вещи в сильно вложенном dict в другое. У меня есть элементы, которые нужно индексировать по 3 значениям, а затем подсчитывать. Поэтому, прежде чем мой цикл, я инициализировать вложенную defaultdict так:Подробнее Pythonic способ подсчета вещей в сильно вложенном defaultdict

from collections import defaultdict 

type_to_count_dic = defaultdict(
     lambda: defaultdict(
      lambda: defaultdict(int) 
     ) 
    ) 

что позволяет мне считать предметы в пределах тугой петлей так:

for a in ...: 
    for b in ...: 
     for c in ...: 
      type_to_count_dic[a][b][c] += 1 

Я чувствую, что инициализирует все эти defaultdict сек очень похож на объявление типа в Java. Есть ли более идиоматический/питонический способ сделать что-то подобное?

ответ

8
from collections import defaultdict 

class _defaultdict(defaultdict): 
    def __add__(self, other): 
     return other 

def CountTree(): 
    return _defaultdict(CountTree) 

>>> t = CountTree() 
>>> t['a'] 
defaultdict(<function CountTree at 0x9e5c3ac>, {}) 
>>> t['a']['b']['c'] += 1 
>>> print t['a']['b']['c'] 
1 
3

Поскольку вы подсчета вещи, вы должны использовать счетчик для самого внутреннего Dict:

import collections 
defaultdict = collections.defaultdict 
Counter = collections.Counter 

x = defaultdict(lambda: defaultdict(Counter)) 

for a in A: 
    for b in B: 
     x[a][b].update(C) 

Использование счетчика даст вам доступ к полезным методам, таким как most_common.

В зависимости от того, что вы намерены делать с этим диктоном, вам может не понадобиться глубокая вложенность. Вместо этого вы можете использовать кортеж для ключа. Например,

import collections 
import itertools as IT 

A = range(2) 
B = 'XYZ' 
C = 'abc' 
x = collections.Counter(IT.product(A, B, C)) 
print(x) 

дает

A = range(2) 
B = 'XYZ' 
C = 'abc' 
x = collections.Counter(IT.product(A, B, C)) 
print(x) 

дает

Counter({(0, 'X', 'c'): 1, (0, 'Z', 'a'): 1, (1, 'Z', 'a'): 1, (1, 'X', 'c'): 1, (1, 'Z', 'b'): 1, (0, 'X', 'b'): 1, (0, 'Y', 'a'): 1, (1, 'Y', 'a'): 1, (0, 'Z', 'c'): 1, (1, 'Z', 'c'): 1, (0, 'X', 'a'): 1, (0, 'Y', 'b'): 1, (1, 'X', 'a'): 1, (1, 'Y', 'b'): 1, (0, 'Z', 'b'): 1, (1, 'Y', 'c'): 1, (1, 'X', 'b'): 1, (0, 'Y', 'c'): 1}) 
2

Я предполагаю, что вы только добавляя к каждому счетчику, когда некоторые кон или встречаются различные значения в зависимости от условий? В противном случае значение каждого счетчика всегда будет равным 1?

Это самое простое решение, которое я могу придумать, это просто создать единый ключ, основанный на кортеже трех значений цикла. Например, примерно так:

dict(((a,b,c),1) for a in A for b in B for c in C) 

Но, как я уже сказал, это просто даст вам 1 в каждом счетчике. Вам нужно заменить в выражении выше некоторого условия или функции вызова, который возвращает что-то более подходящее в зависимости от значений , б и с.

0

У меня была подобная необходимость, и создал следующее:

import json 

from collections import defaultdict 


class NestedDefaultDict(defaultdict): 
    def __init__(self, depth, default=int, _root=True): 
     self.root = _root 
     self.depth = depth 
     if depth > 1: 
      cur_default = lambda: NestedDefaultDict(depth - 1, 
                default, 
                False) 
     else: 
      cur_default = default 
     defaultdict.__init__(self, cur_default) 

    def __repr__(self): 
     if self.root: 
      return "NestedDefaultDict(%d): {%s}" % (self.depth, 
                defaultdict.__repr__(self)) 
     else: 
      return defaultdict.__repr__(self) 


# Quick Example 
core_data_type = lambda: [0] * 10 
test = NestedDefaultDict(3, core_data_type) 
test['hello']['world']['example'][5] += 100 
print test 
print json.dumps(test) 

# Code without custom class. 
test = defaultdict(lambda: defaultdict(lambda: defaultdict(core_data_type))) 
test['hello']['world']['example'][5] += 100 
print test 
print json.dumps(test) 

Если я в конечном итоге его обновления, я также создал суть: https://gist.github.com/KyleJamesWalker/8573350

 Смежные вопросы

  • Нет связанных вопросов^_^