2015-07-30 14 views
6

Jestem obecnie za pomocą defaultdict z Counter jednoznacznie liczyć kilka nieprzewidywalne wartości nieprzewidywalnych klawiszy:Jak użyć konkretnej struktury danych jako default_factory dla defaultdict?

from collections import defaultdict, Counter 

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

To daje mi oczekiwany wynik:

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

Teraz trzeba rozwinąć strukturę wartości w defaultdict i sprawiają, że jest to dict z dwoma kluczami: poprzednim Counter i str:

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

Czy można użyć konkretnej struktury danych (takiej jak powyższa) jako default_factory w defaultdict? Oczekiwany wynik będzie taki, że dla każdego nieistniejącego klucza w defaultdict zostanie utworzony nowy klucz i wartość zainicjowana powyższą strukturą.

+0

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

+0

@jonrsharpe: jest na miejscu, nawet nie myślałem, żeby iść tą drogą. Czy mógłbyś skopiować to do odpowiedzi? – WoJ

Odpowiedz

8

Wystarczy zdefiniować default_factory jako funkcja, która zwraca słownika, który chcesz domyślnie:

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

Jeśli nie są zaznajomieni z lambda, to jest to samo, co:

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

Alternatywnym rozwiązaniem drootang „s odpowiedź jest użycie niestandardowej klasy:

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 (< klasy __main __ NamedCounter w 0x19de808 > {x 'NamedCounter (nazwa = 'licznik X', licznik = licznik ({ 'b' 2}))}.)

Alternatywnie, można przedłużyć Counter włączenie nazwy do licznika samego:

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 (<klasy> {x " '__main __ NamedCounter.' NamedCounter (nazwa = 'licznik x' dyktować = {'b': 2})})

Powiązane problemy