2013-07-04 28 views
8

mam listę, jak podano poniżej -Python Generowanie dynamiczny słownik z listy kluczy

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"] 
value1 = "Roger" 

Jak mogę wygenerować dynamicznego słownika, który można pobrać poniżej -

mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value 

lista może być cokolwiek; Zmienna długość lub składający się z „N” liczbę elementów nieznanych mi ...

Teraz mam inną listę, tak aby Mój słownik powinny zostać odpowiednio zaktualizowane

keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"] 
value2 = 25 

tj Jeśli Keys „osoba”, „Mężczyzna”, „Boy”, „Student”, „id_123” już istnieje, nowy klucz „wiek” należy dołączyć ...

+0

Proponuję dołączyć wszystkie pozycje na liście i użyć wynikowy ciąg jako klucz. Byłoby znacznie łatwiej. – rajpy

+0

Odpowiedzi na to pytanie mogą pomóc: http://stackoverflow.com/questions/16384174/more-pythonic-way-of-counting-things-in-a-heavily-nested-defaultdict – dg123

Odpowiedz

8

Właśnie uczę Pythona, więc mój kod może być niezbyt pythonic, ale tutaj jest mój kod

d = {} 

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"] 
keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"] 
value1 = "Roger" 
value2 = 3 

def insert(cur, list, value): 
    if len(list) == 1: 
     cur[list[0]] = value 
     return 
    if not cur.has_key(list[0]): 
     cur[list[0]] = {} 
    insert(cur[list[0]], list[1:], value) 

insert(d, keyList1, value1) 
insert(d, keyList2, value2) 

{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 3, 'Name': 'Roger'}}}}}} 
+0

To kończy się być bardzo podobne do mojego rozwiązania. Jedna prosta sugestia: unikaj '.has_key' kiedy tylko to możliwe; preferuj szybsze i bardziej zrozumiałe 'jeśli lista [0] nie jest w cur'. – nneonneo

+0

dziękuję, zgadzam się, że jest bardziej czytelny, a czytelność się liczy, ale dlaczego jest szybsza? –

+1

Wypróbuj za pomocą 'timeit'. Na moim komputerze 'in' jest dwa razy szybsze od' .has_key' (0.0672μs vs. 0.117μs). '.has_key' jest wyszukiwaniem metody, natomiast' in' jest wbudowanym, które jest wysyłane znacznie szybciej. – nneonneo

-2
>>> mydict = {} 
>>> keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"] 
>>> value1 = "Roger" 
>>> reduce(lambda x, y: x.setdefault(y, {}), keyList1, mydict) 
{} 
>>> mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value1 

można również zrobić to w jednym kroku jak ten

>>> keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"] 
>>> value2 = 25 
>>> reduce(lambda x,y: x.setdefault(y,{}), keyList2[:-1], mydict).update({keyList2[-1]: value2}) 
+0

>>> mydict {' Osoba ": {'Male': {'Boy': {'Student': {'id_123': {'Nazwa': 'Roger'}}}}}} –

+0

@AhhishekKulkarni, er .. gdzie' redukuje (lambda x, y: x.setdefault (y, {}), keyList1, mydict) 'zależą od liczby elementów lub określonych kluczy? –

1

Stwórz własną klasę pochodną od dict gdzie startowych metoda pobiera listę i pojedynczą wartość jako dane wejściowe i iteracyjne poprzez ustawienie listy kluczy do wartości, zdefiniuj metodę aktualizacji, która pobiera listę i nową wartość, a dla każdej pozycji, która nie jest jeszcze kluczem, ustaw ją na nową wartość (zakładając, że to jest to, czego potrzebujesz) .

Zapomnij ideę

mydict [ "Osoba"] [ "Mężczyzna"] [ "Boy"] [ "Student"] [ "id_123"] [ "nazwa"] = value1`

jak to jest mylące z subindeksów.

4

Można to zrobić poprzez zagnieżdżone defaultdict s:

from collections import defaultdict 

def recursive_defaultdict(): 
    return defaultdict(recursive_defaultdict) 

def setpath(d, p, k): 
    if len(p) == 1: 
     d[p[0]] = k 
    else: 
     setpath(d[p[0]], p[1:], k) 

mydict = recursive_defaultdict() 

setpath(mydict, ["Person", "Male", "Boy", "Student", "id_123", "Name"], 'Roger') 

print mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] 
# prints 'Roger' 

Ma to tę zaletę, że jest miły w stanie napisać

mydict['a']['b'] = 4 

bez konieczności korzystania z setpath pomocnika.

Można to zrobić bez rekurencyjnego defaultdict zbyt:

def setpath(d, p, k): 
    if len(p) == 1: 
     d[p[0]] = k 
    else: 
     setpath(d.setdefault(p[0], {}), p[1:], k) 
0

Próbuję czynienia z podobnym rzeczy, więc mogę zaproponować kilka wskazówek, ale znowu jestem naiwny w Pythonie, więc jest to tylko wytyczna ...

masz listę kluczy , więc na pewno można rozpocząć z pętli iteracji dla każdej wartości, a następnie przypisać wartość

jak

for i in keylist: 
if type(keylist[i]) == dict: 
     do something 
    else: 
     keylist[i] = {} 

w coś zrobić, trzeba zwiększyć i i zmień indeks na [i] [i + 1], a następnie wykonaj to samo do i + n = len (keylist)

0

Jako klucz użyj tuple(keyList1). (Krotki są niezmienne i dlatego mogą być klawiszami dyktującymi).

Będziesz mieć świat bóle głowy z podejściem zagnieżdżonym dyktować. (zagnieżdżone pętle do wyliczenia, starsze dane, gdy hierarchia wymaga zmiany itp.).

Na drugim myśli, być może należy zdefiniować klasę osoba

class Person(object): 
    gender = "Male" 
    group = "Student" 
    id = 123 
    Name = "John Doe" 

następnie wykorzystać listę wszystkich osób i filtrować na przykład z

male_students = [s for s in ALL_PERSONS where s.gender=="Male" and s.group="Student"] 

... dla < = 10000 uczniów powinno być w porządku.

3

Może podklasy dict:

class ChainDict(dict): 
    def set_key_chain(self, keyList, value): 
     t = self 
     for k in keyList[:-1]: 
      t = t.setdefault(k, {}) 
     t.setdefault(keyList[-1], value) 

c = ChainDict() 
c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Name'], 'Roger') 
print c 
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Name': 'Roger'}}}}}} 

c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Age'], 25) 
print c 
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 25, 
     'Name': 'Roger'}}}}}} 
Powiązane problemy