Список вложенного словаря в python

У меня есть следующий список

['item1', 'item2', 'item3', 'item4']

Я хочу построить словарь из приведенного выше списка следующим образом

{
    "item1": {
        "item2": {
            "item3": "item4"
        }
    }
}

Количество элементов в списке динамическое. Словарь будет вложенным словарем, пока не достигнет последнего элемента списка. Есть ли способ в python для этого?

Ответ 1

Простой однострочный:

a = ['item1', 'item2', 'item3','item4']
print reduce(lambda x, y: {y: x}, reversed(a))

Для лучшего понимания вышеуказанный код можно развернуть до:

def nest_me(x, y):
    """
    Take two arguments and return a one element dict with first
    argument as a value and second as a key
    """
    return {y: x}

a = ['item1', 'item2', 'item3','item4']
rev_a = reversed(a) # ['item4', 'item3', 'item2','item1']
print reduce(
    nest_me, # Function applied until the list is reduced to one element list
    rev_a # Iterable to be reduced
)
# {'item1': {'item2': {'item3': 'item4'}}}

Ответ 2

Использовать рекурсию:

In [10]: src = ['item1', 'item2', 'item3','item4']

In [11]: def list2dict(src_list):
    if len(src_list) > 1:
        return {src_list[0] : list2dict(src_list[1:])}
    else:
        return src_list[0]
   ....:     

In [12]: 

In [12]: list2dict(src)
Out[12]: {'item1': {'item2': {'item3': 'item4'}}}

Ответ 3

Используя reduce() функцию для доступа и установки элементов:

try:
    # Python 3 moved reduce to the functools module
    from functools import reduce
except ImportError:
    # Python 2 reduce is a built-in
    pass

def get_target(d, keys):
    return reduce(lambda d, k: d.setdefault(k, {}), keys, d)

def set_target(d, keys, value):
    parent = get_target(d, keys[:-1])
    parent[keys[-1]] = value

result = {}
set_target(result, yourlist[:-1], yourlist[-1])

Функции get_target() и set_target() можно повторно использовать в уже построенных вложенных структурах, они не ограничиваются построением словаря с нуля. Я адаптировал get_target() из ранее связанного сообщения.

Демо:

>>> def get_target(d, keys):
...     return reduce(lambda d, k: d.setdefault(k, {}), keys, d)
... 
>>> def set_target(d, keys, value):
...     parent = get_target(d, keys[:-1])
...     parent[keys[-1]] = value
... 
>>> result = {}
>>> yourlist = ['item1', 'item2', 'item3', 'item4']
>>> set_target(result, yourlist[:-1], yourlist[-1])
>>> result
{'item1': {'item2': {'item3': 'item4'}}}