2012-12-03 12 views
21

Przepraszam, jeśli odpowiedź na to pytanie była wcześniejsza - szukałem rozwiązań, ale być może nie używam poprawnych wyszukiwanych terminów.Ustawianie wartości w zagnieżdżonym słowniku python z podaniem listy indeksów i wartości

W każdym razie staram się programowo ustawić wartość w słowniku, potencjalnie zagnieżdżoną, biorąc pod uwagę listę indeksów i wartość.

Więc na przykład, powiedzmy, że moja lista indeksów jest:

['person', 'address', 'city'] 

i wartość jest

'New York' 

Chcę wskutek słownika obiektów takich jak:

{ 'Person': { 'address': { 'city': 'New York' } } 

Zasadniczo lista reprezentuje "ścieżkę" do zagnieżdżonego słownika.

Myślę, że mogę sam zbudować słownik, ale gdzie się potykam, to jak ustawić wartość. Oczywiście gdybym tylko pisanie kodu dla tego ręcznie byłoby:

dict['Person']['address']['city'] = 'New York' 

ale jak indeks do słownika i ustawić wartość takiego programowo jeśli mam tylko listę indeksów i wartości?

Mam nadzieję, że to ma sens i nie jest zbyt głupie pytanie ... :) Dzięki za pomoc.

+1

Co z 'dict [x] [ y] [z] = wartość "? Skąd masz "wartość"? Co to za dziwaczny format? – kreativitea

+0

@kreativitea Niepoprawnie, ponieważ może mieć liczbę zagnieżdżonych kluczy o zmiennej długości. – Bakuriu

+1

Być może uda ci się uniknąć zagnieżdżania za pomocą kluczy: 'd [tuple (da_list)] = value' –

Odpowiedz

31

Coś takiego może pomóc:

def nested_set(dic, keys, value): 
    for key in keys[:-1]: 
     dic = dic.setdefault(key, {}) 
    dic[keys[-1]] = value 

I można go używać tak:

>>> d = {} 
>>> nested_set(d, ['person', 'address', 'city'], 'New York') 
>>> d 
{'person': {'address': {'city': 'New York'}}} 
+3

To działa pięknie, dziękuję. – peterk

+1

Właśnie uratowałeś mi pracę popołudniową. Dzięki wielkie! – omarish

+2

Jakąkolwiek wskazówkę, dlaczego to działa? (Próbowałem i działa) I dlaczego nie działa czysta pętla for? – charisz

3

Po pierwsze, prawdopodobnie chcesz, aby spojrzeć na setdefault

Jako funkcja Chciałbym napisać go jako

def get_leaf_dict(dict, key_list): 
    res=dict 
    for key in key_list: 
     res=dict.setdefault(key, {}) 
    return res 

To byłyby wykorzystywane jako:

get_leaf_dict(dict, ['Person', 'address', 'city']) = 'New York' 

To może być oczyszczone z obsługą błędów i takie, również używanie *args zamiast pojedynczego argumentu z listą klawiszy może być miłe; ale pomysł jest taki, że można iterować po klawiszach, wyciągając odpowiedni słownik na każdym poziomie.

+0

I dziękuję za to ... Odpowiedź Bakuriu jest nieco bardziej kompleksowa/zwięzła, ale byłeś na tym samym torze i doceniam, jak szybko odpowiedziałeś. – peterk

1

Oto kolejna opcja:

from collections import defaultdict 
recursivedict = lambda: defaultdict(recursivedict) 
mydict = recursivedict() 

I początkowo dostał to stąd: https://stackoverflow.com/a/10218517/1530754.

Całkiem sprytna i elegancka, jeśli mnie pytasz.

+0

Tego właśnie szukałem. dzięki – darkless

1

Oto mój proste rozwiązanie: wystarczy napisać

terms = ['person', 'address', 'city'] 
result = nested_dict(3, str) 
result[terms] = 'New York' # as easy as it can be 

Można nawet zrobić:

terms = ['John', 'Tinkoff', '1094535332'] # account in Tinkoff Bank 
result = nested_dict(3, float) 
result[terms] += 2375.30 

Teraz kulisami:

from collections import defaultdict 


class nesteddict(defaultdict): 
    def __getitem__(self, key): 
     if isinstance(key, list): 
      d = self 
      for i in key: 
       d = defaultdict.__getitem__(d, i) 
      return d 
     else: 
      return defaultdict.__getitem__(self, key) 
    def __setitem__(self, key, value): 
     if isinstance(key, list): 
      d = self[key[:-1]] 
      defaultdict.__setitem__(d, key[-1], value) 
     else: 
      defaultdict.__setitem__(self, key, value) 


def nested_dict(n, type): 
    if n == 1: 
     return nesteddict(type) 
    else: 
     return nesteddict(lambda: nested_dict(n-1, type)) 
Powiązane problemy