2015-07-30 4 views
6

я в настоящее время с помощью defaultdict из Counter однозначно насчитать несколько непредсказуемых значений для непредсказуемых ключей:Как использовать определенную структуру данных как default_factory для defaultdict?

from collections import defaultdict, Counter 

d = defaultdict(Counter) 
d['x']['b'] += 1 
d['x']['c'] += 1 
print(d) 

Это дает мне ожидаемый результат:

defaultdict(<class 'collections.Counter'>, {'x': Counter({'c': 1, 'b': 1})}) 

теперь нужно расширить структуру из значения в defaultdict и сделать его dict с двумя ключами: предыдущие Counter и str:

mystruct = { 
    'counter': collections.Counter(), 
    'name': '' 
} 

Возможно ли использовать конкретную структуру данных (как указано выше) как default_factory в defaultdict? Ожидаемый результат будет заключаться в том, что для каждого несуществующего ключа в defaultdict будет создан новый ключ и значение, инициализированное со структурой выше.

+0

'defaultdict (lambda: {'counter': Counter(), 'name': ''})'? – jonrsharpe

+0

@jonrsharpe: это прямо на месте, я даже не думал идти таким путем. Не могли бы вы скопировать это в ответ? – WoJ

ответ

8

Вам просто нужно определить свой default_factory как функцию, которая возвращает словарь, который вы хотите по умолчанию:

from collections import defaultdict, Counter 
d = defaultdict(lambda: {'counter': Counter(), 'name': ''}) 
d['x']['counter']['b'] += 1 
d['x']['counter']['c'] += 1 
print(d) 

Если вы не знакомы с лямбды, это то же самое, как:

def my_factory(): 
    aDict = {'counter': Counter(), 'name':''} 
    return aDict 
d = defaultdict(my_factory) 
1

альтернативное решение drootang «s ответ использовать пользовательский класс:

from collections import defaultdict, Counter 

class NamedCounter: 
    def __init__(self, name = '', counter = None): 
     self.counter = counter if counter else Counter() 
     self.name = name 

    def __repr__(self): 
     return 'NamedCounter(name={}, counter={})'.format(
       repr(self.name), repr(self.counter)) 

d = defaultdict(NamedCounter) 
d['x'].counter['b'] += 1 
d['x'].counter['b'] += 1 
d['x'].name = 'X counter' 
print(d) 

defaultdict (< класс __main __ NamedCounter в 0x19de808 >, { 'х': NamedCounter (имя = 'Х счетчика', счетчик = счетчик ({ 'B': 2}))}.)

в качестве альтернативы, вы можете расширить Counter включить имя в сам счетчик:

from collections import defaultdict, Counter 

class NamedCounter(Counter): 
    def __init__(self, name = '', dict = None): 
     super(Counter, self).__init__(dict if dict else {}) 
     self.name = name 

    def __repr__(self): 
     return 'NamedCounter(name={}, dict={})'.format(
       repr(self.name), super(Counter, self).__repr__()) 

d = defaultdict(NamedCounter) 
d['x']['b'] += 1 
d['x']['b'] += 1 
d['x'].name = 'X counter' 
print(d) 

defaultdict (< класса >, { 'х' '__main __ NamedCounter.': NamedCounter (имя = 'X счетчик', ДИКТ = {'b': 2})})