Для некоторых пост-обработки, мне нужно, чтобы сгладить структуру, как этотСвести вложенную структуру Dict в наборе данных
{'foo': {
'cat': {'name': 'Hodor', 'age': 7},
'dog': {'name': 'Mordor', 'age': 5}},
'bar': { 'rat': {'name': 'Izidor', 'age': 3}}
}
в этом наборе:
[{'foobar': 'foo', 'animal': 'dog', 'name': 'Mordor', 'age': 5},
{'foobar': 'foo', 'animal': 'cat', 'name': 'Hodor', 'age': 7},
{'foobar': 'bar', 'animal': 'rat', 'name': 'Izidor', 'age': 3}]
Так что я написал эту функцию:
def flatten(data, primary_keys):
out = []
keys = copy.copy(primary_keys)
keys.reverse()
def visit(node, primary_values, prim):
if len(prim):
p = prim.pop()
for key, child in node.iteritems():
primary_values[p] = key
visit(child, primary_values, copy.copy(prim))
else:
new = copy.copy(node)
new.update(primary_values)
out.append(new)
visit(data, { }, keys)
return out
out = flatten(a, ['foo', 'bar'])
Я был не очень доволен, потому что мне нужно использовать copy.copy
для защиты моих входов. Очевидно, что при использовании flatten
не требуется, чтобы входы были изменены.
Затем я подумал об одной альтернативе, которая использует более глобальные переменные (по крайней мере глобальные до flatten
) и использует индекс вместо прямого прохождения primary_keys
до visit
. Однако это не помогает мне избавиться от уродливых первоначальной копии:
keys = copy.copy(primary_keys)
keys.reverse()
Так вот мой окончательный вариант:
def flatten(data, keys):
data = copy.copy(data)
keys = copy.copy(keys)
keys.reverse()
out = []
values = {}
def visit(node, id):
if id:
id -= 1
for key, child in node.iteritems():
values[keys[id]] = key
visit(child, id)
else:
node.update(values)
out.append(node)
visit(data, len(keys))
return out
Есть ли более эффективное осуществление (что позволяет избежать использования copy.copy
)?
Ваше решение работает с моим образцом, но не с моими настоящими данными, которые имеют гораздо больше слоев. Мне нужен рекурсивный алгоритм. – nowox