Вот моя реализация вашей структуры данных с использованием вложенных словарей:
class Tree(dict):
'''/525385/kakov-nailuchshii-sposob-realizatsii-vlozhennyh-slovarei'''
def __missing__(d, k):
v = d[k] = type(d)()
return v
def grow(d, path, v):
ps = map(lambda k: int(k) if k.isdigit() else k, path.split('/'))
reduce(lambda d, k: d[k], ps[:-1], d)[ps[-1]] = v
Проверка этого:
t = Tree()
t.grow('a/0/b/c', 1)
print t
t['a'][2]['b']['c'] = 'string'
print t
t.grow('a/2/b/c', 'new_string')
print t
дает:
{'a': {0: {'b': {'c': 1}}}}
{'a': {0: {'b': {'c': 1}}, 2: {'b': {'c': 'string'}}}}
{'a': {0: {'b': {'c': 1}}, 2: {'b': {'c': 'new_string'}}}}
Но вы хотите, чтобы целочисленные словари были массивами. Подпрограмма ниже проходит через вложенные словари, превращая некоторые из них в списки. Это делает некоторое копирование, чтобы не испортить оригинальные вложенные словари. Я бы использовал это как часть аутсайдера.
import numbers
def keys_all_int(d):
return reduce(lambda r, k: r and isinstance(k, numbers.Integral), d.keys(), True)
def listify(d):
'''
Take a tree of nested dictionaries, and
return a copy of the tree with sparse lists in place of the dictionaries
that had only integers as keys.
'''
if isinstance(d, dict):
d = d.copy()
for k in d:
d[k] = listify(d[k])
if keys_all_int(d):
ds = [{}]*(max(d.keys())+1)
for k in d:
ds[k] = d[k]
return ds
return d
Проверка этого:
t = Tree()
t.grow('a/0/b/c', 1)
print listify(t)
t['a'][2]['b']['c'] = 'string'
print listify(t)
t.grow('a/2/b/c', 'new_string')
print listify(t)
Дает:
{'a': [{'b': {'c': 1}}]}
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'string'}}]}
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'new_string'}}]}
Наконец, если вы имеете дело с JSON, используйте модуль json
:
import json
print json.dumps(listify(t),
sort_keys=True, indent = 4, separators = (',', ': '))
Дает:
{
"a": [
{
"b": {
"c": 1
}
},
{},
{
"b": {
"c": "new_string"
}
}
]
}