2013-05-05 3 views
6

Mein Code muss derzeit Dinge in einem stark verschachtelten dict in einem anderen zählen. Ich habe Artikel, die von 3 Werten indiziert werden müssen und dann gezählt werden. Also, bevor meine Schleife initialisieren ich eine verschachtelte defaultdict wie so:Mehr Pythonic Art der Dinge in einem stark verschachtelten Standarddict zu zählen

from collections import defaultdict 

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

Welche mir die Einzelteile innerhalb einer engen Schleife zu zählen ermöglicht es etwa so:

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

Ich fühle mich wie die Initialisierung alle jene defaultdict s fühlt sich sehr an, als würde man eine Typdeklaration in etwas wie Java machen. Gibt es eine eher idiomatische/pythonische Art, so etwas zu tun?

Antwort

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

Da Sie Dinge zählen, sollten Sie einen Zähler für den am weitesten innen dict verwenden:

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) 

einen Zähler werden Sie wie most_common Zugang zu nützlichen Methoden geben.

Je nachdem, was Sie mit diesem Diktat beabsichtigen, benötigen Sie die tiefe Verschachtelung möglicherweise nicht. Stattdessen könnten Sie ein Tupel für den Schlüssel verwenden. Zum Beispiel

import collections 
import itertools as IT 

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

ergibt

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

ergibt

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

Ich nehme an, Sie sind nur für jeden Zähler addiert, wenn bestimmte con Bedingungen erfüllt sind oder möglicherweise je nach den Bedingungen andere Werte hinzufügen? Sonst wird der Wert jedes Zählers immer 1 sein?

Das heißt, die einfachste Lösung, die ich mir vorstellen kann, besteht darin, ein einzelnes dict zu erzeugen, das auf einem Tupel der drei Schleifenwerte kodiert ist. Zum Beispiel so etwas wie diese:

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

Aber wie gesagt, wird dies geht nur Ihnen in jedem Zähler 1 zu geben. Sie verlassen nun die im Ausdruck oben mit einer Bedingung oder Funktionsaufruf ersetzen müssen, die etwas besser geeignet, je nach den Werten von gibt ein, b und c.

0

Ich hatte ein ähnliches Bedürfnis und erstellt die folgenden:

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) 

Wenn ich es ich auch einen Kern erstellt haben Aktualisierung am Ende: https://gist.github.com/KyleJamesWalker/8573350

Verwandte Themen