Рекурсивная функция возвращает результаты только одной ветви вложенного словаря

#python

#питон #python

Вопрос:

У меня есть ветвящийся вложенный словарь для визуализации данных таксономии видов. Я пытаюсь написать функцию, которая выдает мне все ветви на определенном уровне.

Я пробовал итеративные и рекурсивные функции, но я приблизился только к использованию рекурсивной функции. Однако, в зависимости от того, куда я помещаю инструкции return / print , моя функция либо возвращает None (но печатает правильную информацию), либо возвращает только одну ветвь данных. Используя второй вариант, вывод идеален до тех пор, пока набор данных не разветвится.

 tree = {"k-b":
        {"p-a":
         {"c-a":{"o-a":{}, "o-b":{}},
          "c-b":{"o-a":{}}},
         "p-b":
         {"c-a":{"o-a":{},"o-b":{}}}}}

def branches(tree, level):
    if level == 0:
        #print(tree.keys())
        return tree.keys()
    else:
        for i in tree.keys():
             return branches(tree[i], level-1)

print(branchNumber(tree, 2))
  

Я ожидаю, что для уровня 2 [['c-a', 'c-b'], ['c-a']] (это не обязательно должен быть массив массивов, и мне все равно, есть ли у него dict_keys () или что-то еще вокруг него)

На самом деле я получаю dict_keys(['c-a', 'c-b']) , что исключает вторую ветвь

В качестве альтернативы, если я удалю ‘return’ перед рекурсивным вызовом ветвей и раскомментирую оператор print, он печатает:

 dict_keys(['c-a', 'c-b'])
dict_keys(['c-a']) 
  

Это именно тот результат, который я хочу, но функция возвращает None поэтому я не могу сохранить эту информацию для будущих приложений

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

1. Ваш return внутренний for цикл, конечно, возвращается только один раз, для первого элемента в цикле, поэтому вы никогда не увидите другие элементы.

Ответ №1:

Ваш код всегда возвращает первый элемент в цикле, поэтому ваш алгоритм завершается преждевременно и не исследует все необходимые ветви. Вы могли бы yield использовать результаты для создания функции генератора (среди других подходов):

 tree = {"k-b":
        {"p-a":
         {"c-a":{"o-a":{}, "o-b":{}},
          "c-b":{"o-a":{}}},
         "p-b":
         {"c-a":{"o-a":{},"o-b":{}}}}}

def branches(tree, level):
    if level == 0:
        yield list(tree.keys())
    elif level > 0:
        for v in tree.values():
            yield from branches(v, level - 1)

for i in range(4):
    print(f"level {i}:", list(branches(tree, i)))
  

Вывод:

 level 0: [['k-b']]
level 1: [['p-a', 'p-b']]
level 2: [['c-a', 'c-b'], ['c-a']]
level 3: [['o-a', 'o-b'], ['o-a'], ['o-a', 'o-b']]
  

Строка elif level > 0: является оптимизацией, позволяющей избежать углубления в дерево, чем необходимо.

Кроме того, for i in tree.keys() , тогда tree[i] доступ к значению мог бы быть понятнее как for v in tree.values() .

Ответ №2:

Возможно, вы захотите вернуть список всех элементов на этом уровне:

 tree = {"k-b":
        {"p-a":
         {"c-a":{"o-a":{}, "o-b":{}},
          "c-b":{"o-a":{}}},
         "p-b":
         {"c-a":{"o-a":{},"o-b":{}}}}}

def branches(tree, level):
    if level == 0:
        #print(tree.keys())
        return tree.keys()
    else:
        return [branches(tree[i], level-1) for i in tree.keys()]

print(branches(tree, 2))
  

Вывод:

 [[dict_keys(['c-a', 'c-b']), dict_keys(['c-a'])]]
  

Ответ №3:

Похоже, вы хотите вернуть список всех ветвей. Один из способов сделать это — использовать понимание списка:

 def branches(tree, level):
    if level == 0:
        #print(tree.keys())
        return tree.keys()
    else:
        return [branches(tree[i], level-1) for i in tree.keys()]
  

Обратите внимание, что это вернет глубоко вложенный список. Сглаживание оставлено в качестве упражнения для читателя.

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

1. Вы уверены, что хотите обернуть список вокруг каждого уровня, по которому вы спускаетесь в дереве? Например. branches(tree, 3) # => [[[dict_keys(['o-a', 'o-b']), dict_keys(['o-a'])], [dict_keys(['o-a', 'o-b'])]]]