генерирование файла в стиле config из списка словарей наиболее питоническим способом - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть список словарей как,

[{'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'
    }
}

Мне сказали, что это формат, используемый для записи конфигурации.файлы для любой программы.Мне просто любопытно, что могло бы быть наилучшим способом создания файла из этого списка словарей.

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Не очень элегантно, но вы можете собрать свои элементы в collections.defaultdict(), а затем вывести пути к словарям в новый файл.

Основная идея состоит в том, чтобы сначала собрать ваши корневые родительские идентификаторы со значением 0, добавить к этим корням исходные дочерние словари.Вы можете использовать последнее значение в каждом списке для родительского идентификатора самого последнего добавленного элемента.

Демонстрация:

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'
    }
}

Примечание: Этоявляется итеративным, а не рекурсивным решением.

0 голосов
/ 27 декабря 2018

Вы можете рекурсивно вывести разделы, чей parent_sec_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

Если предположить, что ваш примерный список dict хранится как переменная sections, тогда'\n'.join(transform(sections)) вернется:

apple
{
    'key1': 'val1'
    orange
    {
        'key3': 'val3'
        grape
        {
            'key5': 'val5'
        }
    }
}
banana
{
    'key2': 'val2'
    guava
    {
        'key4': 'val4'
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...