2013-07-04 2 views
8

У меня есть список, как указано ниже -Python Сформировать динамический словарь из списка ключей

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

Как создать динамический словарь, который может извлекаться, как показано ниже -

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

список может быть любым; Переменная длина или состоящий из «N» количество элементов, неизвестных мне ...

Теперь у меня есть еще один список, так что мой словарь должен быть обновлен соответственно

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

т.е. если Кис «лицо», «Мужской», «Мальчик», «Студент», «id_123» уже существует, должен быть добавлен новый ключ «возраст» ...

+0

Я хотел бы предложить, чтобы добавить все элементы в списке и использовать полученную строку в качестве ключа. Это было бы намного проще. – rajpy

+0

Ответы на этот вопрос могут помочь: http://stackoverflow.com/questions/16384174/more-pythonic-way-of-counting-things-in-a-heavily-nested-defaultdict – dg123

ответ

8

Я только учусь питона, так что мой код может быть не очень вещий, но вот мой код

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

Это в конечном итоге очень похоже на мое решение. Одно простое предложение: избегайте '.has_key', когда это возможно; предпочитают более быстрый и понятный 'if list [0] не в cur'. – nneonneo

+0

спасибо, я согласен, что это более читаемо и читаемость, но почему это быстрее? –

+1

Попробуйте использовать 'timeit'. На моем компьютере 'in' в два раза быстрее, чем' .has_key' (0.0672 мкс против 0.117 мкс). '.has_key' - это поиск метода, тогда как' in' является встроенным, который отправляется намного быстрее. – 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 

Вы также можете сделать это за один шаг, как этот

>>> 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 {' Person ': {' Male ': {' Boy ': {' Student ': {' id_123 ': {' Name ':' Roger '}}}}}}} –

+0

@AbhishekKulkarni, er .. где «уменьшить» (лямбда x, y: x.setdefault (y, {}), keyList1, mydict) 'зависит от количества элементов или конкретных ключей? –

1

Создайте свой собственный класс, производный от Dict где инициализации метод принимает список и одно значение в качестве входных данных и итерации по списку, устанавливая ключи для значения, определите метод обновления, который принимает список и новое значение, и для каждого элемента, который еще не является ключом, установленным для нового значения (при условии, что это то, что вам нужно) ,

Забудьте идею

mydict [ "Person"] [ "Мужской"] [ "Boy"] [ "Student"] [ "id_123"] [ "Name"] = value1`

как это сбивает с толку с субиндексов.

4

Вы можете сделать это путем вложенными 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' 

Это имеет хорошее преимущество, чтобы быть в состоянии написать

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

без того, чтобы использовать setpath помощника.

Вы можете сделать это без рекурсивного defaultdict слишком:

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

Я пытаюсь иметь дело с подобным материалом, так что я могу предложить некоторые рекомендации, но опять же я наивная в Python, так что это просто руководство ...

у вас есть список ключей , так что вы можете определенно начать с петлей итерации для каждого значения, а затем присвоить значение

как

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

в делать что-то, что вам нужно, чтобы увеличить i и изменить индекс на [i] [i + 1], а затем следовать за ним до i + n = len (keylist)

0

Использовать tuple(keyList1) как ключ. (кортежи неизменяемы и поэтому могут быть диктофонными клавишами).

У вас будет мир головной боли с вложенным диктовским подходом. (вложенные циклы для перечисления, устаревшие данные, когда необходимо изменить иерархию и т. д.).

На второй мысли, может быть, вы должны определить класс человека

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

затем использовать список всех лиц, и фильтр, например, с

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

... для < = 10000 студентов, вы должны быть в порядке.

3

Может быть, вы могли бы подкласс 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'}}}}}} 
Смежные вопросы