LINUX.ORG.RU

Как проитерировать ключи в словаре неизвестной вложенности в python

 


0

1

Сап, народ. С прошлой темы про содержание своего проекта много для себя подчеркнул. Решил попробовать разделить проект на файлы и импортировать их в основной. Щас вроде получше.

Есть такая ситуация. У меня есть функция, допустим

def find_all_keys(input_dict):
    keys_list = [i for i in input_dict.keys() if i.startswith("lib")]
    return keys_list

Пример условный, понятно, что для такой мелочи функция может быть не нужна. Так вот я буду в эту функцию загонять по одному объекту - словарю, в котором мне заранее неизвестно количество пар. Но если с этим я могу еще заранее продумать, как посчитать количество итераций для дальнейшего использования списка из возврата, то в случае с итерацией, когда внутри словаря могут быть вложенные словари неизвестной глубины и неизвестного количества, я не знаю что делать. Каким образом я могу проще всего решить такой случай? В итоге нужно получить список (именно список, а не множество) со всеми ключами словаря включая вложенные словари любой глубины.

def all_keys(input_dict):
    if isinstance(input_dict, dict):
        keys = [* input_dict.keys(), ]
        for key, val in input_dict.items():
            keys.extend(all_keys(val))
        return keys
    else:
        return []
vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от vvn_black

Или в одну строку:

from functools import reduce

def all_keys(input_dict):
    return isinstance(input_dict, dict) \
        and reduce(lambda a, c: a + all_keys(input_dict[c]),
                   input_dict.keys(),
                   [*input_dict.keys(), ]) \
        or []
vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от vvn_black

Какой адок. Зачем-то reduce притащил, лямбды какие-то, ещё и висячие переносы добавил, офигеть вообще. Хотел повыпендриваться, а превратил код в говно.

beresk_let ★★★★★
()

Как-то так:

def find_all_keys(input_dict: dict) -> list:
    result = []
    for key, val in input_dict.items():
        if key.startswith('lib'):
            result.append(key)
        if isinstance(val, dict):
            result.extend(find_all_keys(val))
    return result

В 1 строчку:

def find_all_keys(input_dict: dict, sw='lib') -> list:
    return (lambda x=[]: [k for k, v in input_dict.items() if (k.startswith(sw) and x.append(k)) or (isinstance(v, dict) and x.extend(find_all_keys(v)))] or x)()

KillTheCat ★★★★★
()
Последнее исправление: KillTheCat (всего исправлений: 1)
from typing import Any, Dict, List


def all_keys(some_dict: Dict[str, Any]) → List[str]:
    if not isinstance(some_dict, dict):
        return []

    keys = []
    for key, value in some_dict.items():
        if key.startswith('lib'):
            keys.append(key)
        keys.extend(all_keys(value))

    return keys
beresk_let ★★★★★
()
Ответ на: комментарий от steemandlinux

тип возвращаемого значения (должно быть "->")

Sahas ★★★★☆
()
Последнее исправление: Sahas (всего исправлений: 1)
Ответ на: комментарий от steemandlinux

Да, выше верно ответили: я не заметил, что автоформатирование превратило –> в .

beresk_let ★★★★★
()

Предложенные варианты с рекурсией, что накладывает ограничение на глубину вложенности. Вариант без рекурсии:

def all_keys(input_dict):
    def iterate_dict(idict):
        keys = []
        values = []
        for key, value in idict.items():
            if type(value) is dict:
                values.append(value)
            keys.append(key)
        return keys, values
    
    result, values = iterate_dict(input_dict)
    while values:
        for value in values:
            keys, values = iterate_dict(value)
            result.extend(keys)
    return result
InterVi ★★★★★
()

Немного рекурсии

def find_all_keys(input_dict):                                                                      
    result = []                                                                                     
    for k, v in input_dict.items():                                                                 
        if isinstance(v, dict):                                                                     
            result.append(k)                                                                        
            result.extend(find_all_keys(v))                                                         
        else:                                                                                       
            result.append(k)                                                                        
    return result 
pod ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.