Можно ли итеративно добавлять другой уровень ключей в словарь для создания вложенного словаря?

#python #dictionary #for-loop

#python #словарь #для цикла

Вопрос:

Итак, моя идея состоит в том, чтобы сгенерировать словарь таким образом:

 my_dict = {}

for x in range(len(something)):
   for y in range(len(something_else)):
        my_dict[x] = {}
        my_dict[x][y] = {key: value}
 

Однако, когда я пытаюсь сделать это так, я всегда получаю сообщение об ошибке:

KeyError: 0 или KeyError: ‘0’, если я использую строки вместо целых чисел.

Есть идеи, что я могу делать неправильно?

Комментарии:

1. Этот код не выдаст эту ошибку. Это когда вы используете словарь позже? Вы my_dict[x] заменяете пустой словарь в каждом цикле.

Ответ №1:

Делая то, что вы делаете, вы «стираете» my_dict[x] в каждом y цикле.

Попробуйте:

 my_dict = {}

for x in range(len(something)):
   for y in range(len(something_else)):
        d = my_dict.setdefault(x, {})
        d[y] = {key: value}
 

Или:

 my_dict = {}

for x in range(len(something)):
    my_dict[x] = {}
    for y in range(len(something_else)):
        my_dict[x][y] = {}
        for z in range(len(other)):
            my_dict[x][y][z] = {key: value}
 

Комментарии:

1. Хорошо, и как мне поступить, если у меня есть 3 цикла for? Будет ли это что-то вроде этого: d = my_dict.setdefault(x, {}) d[y][z] = {key: value}

2. Что вам нужно помнить, так это то, что вы можете либо инициализировать параметр «узел» за один шаг до цикла, который вы будете использовать (сразу после первого цикла for вы инициализируете уровень 1 с помощью пустого dict), либо использовать setdefault, чтобы предотвратить запись поверх чего-либо существующего, но дать значение по умолчанию, если нет.

3. Но как мне инициализировать узел dict перед циклом, если я все еще хочу, чтобы он повторялся в цикле for . Я предполагаю, что для первого это будет выглядеть примерно так my_dict[x] = {} , или я ошибаюсь?

4. Это кажется хрупким и не будет обобщаться на неизвестный уровень вложенности (например, рекурсия)

5. Очевидно, вы знаете, что рассмотрение рекурсии — это не то же самое, что рассмотрение циклов, верно? Если вы хотите неизвестный уровень вложенности с помощью рекурсии, используйте рекурсию.

Ответ №2:

Вы можете легко создать произвольно вложенный словарь, используя collections.defaultdict :

 from collections import defaultdict

make_dict = lambda: defaultdict(make_dict)
my_dict = make_dict()
 
 my_dict[1][2][3] = 4  # wrap this inside a nested loop as deep as you like
my_dict

defaultdict(<function __main__.<lambda>()>,
            {1: defaultdict(<function __main__.<lambda>()>,
                         {2: defaultdict(<function __main__.<lambda>()>,
                                      {3: 4})})})
 

Комментарии:

1. Мне всегда нравится это удивительно простое решение. Я бы назвал функцию make_tree or even Tree и определил ее как функцию, а не как лямбда.

2. @PeterWood как бы вы это сделали?

3. @Omar Что делает? Определение его как функции? def make_dict(): return defaultdict(make_dict)