【问题标题】:generating config styled file from list of dictionaries in most pythonic way以大多数pythonic方式从字典列表生成配置样式文件
【发布时间】:2019-05-25 05:12:16
【问题描述】:

我有一个字典列表,

[{'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(零),那么它是一个父字典,否则它是该部分 id 提到的字典的子字典。
现在从上面的字典列表中,我被要求实现以下格式(是的,我被问到,是采访的一部分):

apple
{
    'key1': 'val1'

    orange
    {
        'key3': 'val3'

        grape
        {
            'key5': 'val5'
        }
    }

}

banana
{
    'key2': 'val2'

    guava
    {
        'key4': 'val4'
    }
}

有人告诉我这是用于为任何程序编写配置文件的格式。 我只是好奇从这个字典列表中生成文件的最佳方法是什么。

【问题讨论】:

  • 看起来像树实现一样可以工作。
  • 这个配置文件是特定格式吗?就像已经存在的一样。或者它是公司自己创造的一种适当的格式。
  • @RoadRunner 不是我被告知的,基本上每个键值对都会有一个标签(在本例中为 sec_name),然后是该标签下的键值对跨度>

标签: python python-3.x python-2.7 list dictionary


【解决方案1】:

您可以递归地输出 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'
    }
}

【讨论】:

    【解决方案2】:

    不是很优雅,但是您可以在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'
        }
    }
    

    注意:这是一种迭代解决方案,而不是递归解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-21
      • 2022-12-22
      • 2014-03-28
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2012-12-24
      相关资源
      最近更新 更多