2014-07-22 12 views
7

W jaki sposób możemy uzyskać rekurencyjny dostęp do zagnieżdżonych dyktorów, w ogólnym przypadku?Pythoniczny sposób dostępu do rekurencyjnie zagnieżdżonego dyktafonu

from collections import defaultdict 

D = lambda: defaultdict(D) 
d = D() 

keys = ['k1', 'k2', 'k3'] 
value = 'v' 

if len(keys) == 3: 
    k1, k2, k3 = keys 
    d[k1][k2][k3] = value 
else: 
    ??? 

jadę w dół jakąś straszną drogę reduce, d.__getitem__ i d.__setitem__ ale czuł, że musi na pewno być bardziej elegancki sposób ...

+0

Dobre znalezisko @Dave. Twoje wyszukiwanie jest lepsze niż wyszukiwanie przez SO podobnych pytań. – Gerrat

+0

Rzeczywiście, dobre znalezisko. Zamykam moje własne pytanie jako duplikat ... :) – wim

Odpowiedz

3

To dość brzydki, ale to działa:

def set_val(d, keys, val): 
    reduce(lambda x,y: x[y], keys[:-1], d)[keys[-1]] = val 

wersja Nieco bardziej czytelny:

def set_val(d, keys, val): 
    last = keys[-1] # Key we want to set val on 
    search_keys = keys[:-1] # Keys we need to traverse 
    reduce(lambda x,y: x[y], search_keys, d)[last] = val 

Zastosowanie:

>>> from collections import defaultdict 
>>> D = lambda: defaultdict(D) 
>>> d = D() 
>>> set_val(d, ['k1', 'k2', 'k3'], "hi") 
>>> d 
defaultdict(<function <lambda> at 0x7fbd365ac7d0>, {'k1': defaultdict(<function <lambda> at 0x7fbd365ac7d0>, {'k2': defaultdict(<function <lambda> at 0x7fbd365ac7d0>, {'k3': 'hi'})})}) 
>>> d['k1']['k2']['k3'] 
'hi' 

wykorzystuje reduce osiągnąć najbardziej wewnętrznych żądany dict (keys[:-1]), a następnie określa ostateczną klucza z listy do żądanej wartości (output_of_reduce[keys[-1]] = val).

Zauważ, że w Pythonie 3 potrzebujesz od functools import reduce, aby go użyć.

Oto kod rozszerzony dla jasności:

def set_val(d, keys, val): 
    out = d 
    for k in keys[:-1]: 
     out = out[k] 
    out[keys[-1]] = val 
+0

to działa, ale mam nadzieję, że jest bardziej elegancki pomysł .. – wim

2

mógłby po prostu użyć rekursji. Nie można powiedzieć, że jest ona bardziej elegancka lub bardziej pytonowa niż zapętlanie, czy też użycie funkcji zmniejszania.

def assign(dct, keylist, value): 
    if not keylist: 
     dct = value 
    else: 
     dct[keylist[0]] = assign(dct[keylist[0]], keylist[1:], value) 
    return dct 


if __name__ == '__main__': 
    from collections import defaultdict 
    D = lambda: defaultdict(D) 
    d = D() 
    keys = ['k1', 'k2', 'k3'] 
    value = 'v' 
    assign(d, keys, value) 
    print d['k1']['k2']['k3'] 

[prints] 'v' 
Powiązane problemy