我有一个字典列表,
[{'section_id': 1,
'parent_sec_id': 0,
'sec_name': 'apple',
'key1': 'val1'},
{'section_id': 2,
'parent_sec_id': 0,
'sec_name': 'banana',
'key2': 'val2'},
{'section_id': 3,
'parent_sec_id': 1,
'sec_name': 'orange',
'key3': 'val3'},
{'section_id': 4,
'parent_sec_id': 2,
'sec_name': 'guava',
'key4': 'val4'},
{'section_id': 5,
'parent_sec_id': 3,
'sec_name': 'grape',
'key5': 'val5'}]
每本词典的词典标识符为'section_id',关键字为'parent_section_id',用于指示其是否为其他词典的子词典。因此,基本上来说,如果将parent_section_id设置为0(零),则其为父字典,否则为该子句提及的字典的子代。
现在,从上面的词典列表中,我被要求实现以下格式(是的,我被要求参加面试):
apple
{
'key1': 'val1'
orange
{
'key3': 'val3'
grape
{
'key5': 'val5'
}
}
}
banana
{
'key2': 'val2'
guava
{
'key4': 'val4'
}
}
有人告诉我,这是用于编写任何程序的配置文件的格式。 我只是想知道从该词典列表生成文件的最佳方法是什么。
答案 0 :(得分:0)
您可以递归输出parent_sec_id
与给定父ID匹配的节,并缩进子级的输出:
def transform(sections, parent=0):
output = []
indent = ' ' * 4
for section in sections:
if section['parent_sec_id'] == parent:
output.extend((section['sec_name'], '{'))
for key, value in section.items():
if key not in ('section_id', 'parent_sec_id', 'sec_name'):
output.append("%s'%s': '%s'" % (indent, key, value))
output.extend(indent + line for line in transform(sections, section['section_id']))
output.append('}')
return output
假设您的字典样本列表存储为变量sections
,则'\n'.join(transform(sections))
将返回:
apple
{
'key1': 'val1'
orange
{
'key3': 'val3'
grape
{
'key5': 'val5'
}
}
}
banana
{
'key2': 'val2'
guava
{
'key4': 'val4'
}
}
答案 1 :(得分:0)
不太优雅,但是您可以将项目收集在collections.defaultdict()
中,然后将字典路径输出到新文件。
基本思想是首先收集值为0的根父ID,然后将后续的子词典添加到这些根中。您可以将每个列表中的最后一个值用作最近添加的项的父ID。
演示:
from collections import defaultdict
def group_sections(data, parent_id, section_id, root_id = 0):
"""Groups sections into dictionary of lists, connecting on parent keys"""
groups = defaultdict(list)
# Separate root and rest of children
roots = [dic for dic in data if dic[parent_id] == root_id]
children = [dic for dic in data if dic[parent_id] != root_id]
# Add roots first
for root in roots:
groups[root[section_id]].append(root)
# Append children next
for child in children:
for key, collection in list(groups.items()):
# Get most recently added child
recent = collection[-1]
# Only add child if equal to parent
if child[parent_id] == recent[section_id]:
groups[key].append(child)
# Filter out result dictionary to not include parent and section ids
return {
k1: [
{k2: v2 for k2, v2 in d.items() if k2 != parent_id and k2 != section_id}
for d in v2
]
for k1, v2 in groups.items()
}
def write_config_file(filename, data, name_key):
"""Write config file, using dictionary of lists"""
# Writes n tabs to string
tab_str = lambda n: "\t" * n
with open(filename, mode="w") as config_file:
for group in data.values():
tabs = 0
for dic in group:
for key in dic:
# Write name key
if key == name_key:
config_file.write(
"%s%s\n%s{\n" % (tab_str(tabs), dic[key], tab_str(tabs))
)
tabs += 1
# Otherwise write key-value pairs
else:
config_file.write(
"%s'%s': '%s'\n" % (tab_str(tabs), key, dic[key])
)
# Write ending curly braces
for i in range(tabs - 1, -1, -1):
config_file.write("%s}\n" % (tab_str(i)))
if __name__ == "__main__":
list_dicts = [
{"section_id": 1, "parent_sec_id": 0, "sec_name": "apple", "key1": "val1"},
{"section_id": 2, "parent_sec_id": 0, "sec_name": "banana", "key2": "val2"},
{"section_id": 3, "parent_sec_id": 1, "sec_name": "orange", "key3": "val3"},
{"section_id": 4, "parent_sec_id": 2, "sec_name": "guava", "key4": "val4"},
{"section_id": 5, "parent_sec_id": 3, "sec_name": "grape", "key5": "val5"},
]
data = group_sections(data=list_dicts, parent_id="parent_sec_id", section_id="section_id")
write_config_file(filename='config', data=data, name_key='sec_name')
配置文件:
apple
{
'key1': 'val1'
orange
{
'key3': 'val3'
grape
{
'key5': 'val5'
}
}
}
banana
{
'key2': 'val2'
guava
{
'key4': 'val4'
}
}
注意:这是一种迭代解决方案,而不是递归解决方案。