defaultdict의 중첩 된 defaultdict


129

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? , 이것은 두 가지 수준의 기본 결정을 수행하는 방법이었습니다.

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



2
실제로는 ... 질문에 정보를 추가하여 이유를 나타냅니다. 유용한 질문이지만.
Corley Brigman

답변:


168

임의의 수의 레벨의 경우 :

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)

1
정말 완벽한 예입니다. 감사합니다. 데이터를 json에서 defaultdict의 defaultdict로로드하는 경우로 확장 할 수 있습니까?
David Belohrad

4
하나의 메모. 산 세척 중에이 코드를 사용하려고하면 lambda작동하지 않습니다.
Viacheslav Kondratiuk

167

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

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

defaultdict(lambda: defaultdict(dict))

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

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

3
defaultdict (lambda : defaultdict (list)) 올바른 형식?
Yuvaraj Loganathan

죄송합니다. 예, 사전과 같은 객체를 반환하지만 호출 할 수 lambda있기 때문에 양식이 정확 defaultdict(something)합니다 defaultdict. 감사합니다!
크리스 W.

4
이것은 다른 질문의 가능한 중복으로 표시되었지만 ... 원래 질문이 아닙니다. 나는 두 가지 수준의 기본 결정을 만드는 방법을 알고 있었다. 내가 몰랐던 것은 그것을 재귀 적으로 만드는 방법이었습니다. 이 답변은 실제로 stackoverflow.com/questions/5029934/…
Corley Brigman

람다 접근법의 한 가지 단점은 그것이 생성하는 객체를 피클 할 수 없다는 것입니다. 그러나 dict(result)피클 전에 규칙적으로 캐스팅하여이 문제를 해결할 수 있습니다.
CpILL

54

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

tree = lambda: defaultdict(tree)

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


22

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()

4
나는 이것에 대해 생각해야 할 것이다 (조금 더 복잡하다). 하지만 요점은 x = tree ()를 수행하면 나중에 누군가가 와서 tree = None을 수행한다고 생각합니다.
Corley Brigman

11

또한 무한 중첩 및 올바른 형식을 지원하는 더 많은 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': {}}

1
깔끔한! 나는의 통과를 추가 *args하고 **kwargs같은 기능을 허용하는 defaultdict, 즉 키워드 인자와 딕셔너리를 만들 수 있습니다. 이는 전달하는 데 유용 NestedDefaultDictjson.load
치프 리안 Tomoiagă

0

다음은 재귀 기본 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, {})

0

나는 앤드류의 대답에 근거했습니다 . 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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.