[python] defaultdict의 중첩 된 defaultdict

defaultdict를 defaultdict의 기본값으로 만드는 방법이 있습니까? (예 : 무한 레벨 재귀 defaultdict?)

할 수 있기를 원합니다 :

x = defaultdict(...stuff...)
x[0][1][0]
{}

그래서 할 수는 x = defaultdict(defaultdict)있지만 두 번째 수준 일뿐입니다.

x[0]
{}
x[0][0]
KeyError: 0

이를 수행 할 수있는 레시피가 있습니다. 그러나 일반적인 defaultdict 인수를 사용하여 간단하게 수행 할 수 있습니까?

이것은 무한 레벨 재귀 defaultdict를 수행하는 방법을 묻기 때문에 Python과 다릅니다 : defaultdict의 defaultdict? , 이것은 두 가지 수준의 기본 결정을 수행하는 방법이었습니다.

아마도 다발 패턴을 사용하게 될 것입니다 .



답변

임의의 수의 레벨의 경우 :

def rec_dd():
    return defaultdict(rec_dd)

>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}

물론 람다 로이 작업을 수행 할 수도 있지만 람다는 읽기 쉽지 않습니다. 어쨌든 다음과 같습니다.

rec_dd = lambda: defaultdict(rec_dd)


답변

여기에있는 다른 답변 defaultdict은 “무한한 많은”을 포함하는를 만드는 방법을 알려 defaultdict주지만, 처음에는 두 가지 깊이의 기본 결정을 내릴 필요가 있다고 생각하는 것을 다루지 않습니다.

당신은 찾고 있었을 것입니다 :

defaultdict(lambda: defaultdict(dict))

이 구성을 선호하는 이유는 다음과 같습니다.

  • 재귀 솔루션보다 더 명확하므로 독자가 이해할 수 있습니다.
  • 이것은의 “잎”수 defaultdict사전이 아닌 다른 일, 예를 들어, : 할 defaultdict(lambda: defaultdict(list))또는defaultdict(lambda: defaultdict(set))

답변

이를위한 멋진 트릭이 있습니다.

tree = lambda: defaultdict(tree)

그런 다음로을 만들 수 x있습니다 x = tree().


답변

BrenBarn의 솔루션과 유사하지만 변수 이름이 tree두 번 포함되어 있지 않으므로 변수 사전을 변경 한 후에도 작동합니다.

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))

그런 다음 각각의 새로운 만들 수 x와를 x = tree().


를 들어 def버전, 우리는 경우 기존 인스턴스가 작동 중지 결함에서 데이터 구조를 보호하기 위해 함수 클로저 범위를 사용할 수있는 tree이름이 반등이다. 다음과 같이 보입니다 :

from collections import defaultdict

def tree():
    def the_tree():
        return defaultdict(the_tree)
    return the_tree()


답변

또한 무한 중첩 및 올바른 형식을 지원하는 더 많은 OOP 스타일 구현을 제안합니다 repr.

class NestedDefaultDict(defaultdict):
    def __init__(self, *args, **kwargs):
        super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)

    def __repr__(self):
        return repr(dict(self))

용법:

my_dict = NestedDefaultDict()
my_dict['a']['b'] = 1
my_dict['a']['c']['d'] = 2
my_dict['b']

print(my_dict)  # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}}


답변

다음은 재귀 기본 dict를 일반 dict로 변환하는 재귀 함수입니다.

def defdict_to_dict(defdict, finaldict):
    # pass in an empty dict for finaldict
    for k, v in defdict.items():
        if isinstance(v, defaultdict):
            # new level created and that is the new value
            finaldict[k] = defdict_to_dict(v, {})
        else:
            finaldict[k] = v
    return finaldict

defdict_to_dict(my_rec_default_dict, {})


답변

나는 앤드류의 대답에 근거했습니다 . json 또는 기존 dict에서 nester defaultdict로 데이터를로드하려는 경우 다음 예제를 참조하십시오.

def nested_defaultdict(existing=None, **kwargs):
    if existing is None:
        existing = {}
    if not isinstance(existing, dict):
        return existing
    existing = {key: nested_defaultdict(val) for key, val in existing.items()}
    return defaultdict(nested_defaultdict, existing, **kwargs)

https://gist.github.com/nucklehead/2d29628bb49115f3c30e78c071207775