Как мне соединить значения вложенного словаря Python? - PullRequest
4 голосов
/ 29 марта 2010

Предположим, у меня есть словарь, и он внутри со словарями. Я хочу соединить все значения этого словаря, рекурсивно?

' '.join(d.values())

Это работает, если нет гнезд.

Ответы [ 4 ]

7 голосов
/ 29 марта 2010

Следующие работы для любых нерекурсивных вложенных диктов:

def flatten_dict_values(d):
    values = []
    for value in d.itervalues():
        if isinstance(value, dict):
            values.extend(flatten_dict_values(value))
        else:
            values.append(value)
    return values

>>> " ".join(flatten_dict_values({'one': 'not-nested',
...                                'two': {'three': 'nested',
...                                        'four': {'five': 'double-nested'}}}))
'double-nested nested not-nested'

Редактировать: Поддержка рекурсивных диктов

Если вам нужно поддерживать диктанты с самоссылкой, вам нужно расширить приведенный выше код, чтобы отслеживать все обработанные дикты и убедиться, что вы никогда не пытаетесь обработать словарь, который вы уже видели. Ниже приведен достаточно дешевый, но читаемый способ сделать это:

def flatten_dict_values(d, seen_dict_ids=None):
    values = []
    seen_dict_ids = seen_dict_ids or set()
    seen_dict_ids.add(id(d))
    for value in d.itervalues():
        if id(value) in seen_dict_ids:
            continue
        elif isinstance(value, dict):
            values.extend(flatten_dict_values(value, seen_dict_ids))
        else:
            values.append(value)
    return values

>>> recursive_dict = {'one': 'not-nested',
...                   'two': {'three': 'nested'}}
>>> recursive_dict['recursive'] = recursive_dict
>>> " ".join(flatten_dict_values(recursive_dict))
'nested not-nested'
4 голосов
/ 29 марта 2010

Попробуйте что-нибудь вместе

def flatten(d):
    ret = []

    for v in d.values():
        if isinstance(v, dict):
            ret.extend(flatten(v))
        else:
            ret.append(v)

    return ret

my_dict = {1: 'bar', 5: {6: 'foo', 7: {'cat': 'bat'}}}
assert ' '.join(flatten(my_dict)) == 'bar foo bat'
1 голос
/ 29 марта 2010

Это будет работать с вложенными итерациями другого типа, кроме dict, если настроено правильно:

Прототипы '

def should_iter_fnc(it):
    """returns 'True' if 'it' is viewed as nested"""
    raise NotImplementedError

def join_fnc(itr):
    """transform an iterable 'itr' into appropriate object"""
    raise NotImplementedError

def values_fnc(itr):
    """get the list of 'values' of interest from iterable 'itr'"""
    raise NotImplementedError

Сама функция

def recursive_join(smth, join_fnc, should_iter_fnc, values_fnc):
    if should_iter_fnc(smth):
        return join_fnc([
                 recursive_join(it, join_fnc, should_iter_fnc, values_fnc)
                 for it in values_fnc(smth)
                 ])
    else:
        return smth

дает:

>>>
def should_iter(it):
    """Returns 'True', if 'it' is 'iterable' but not an 'str' instance"""
    if isinstance(it, str):
        return False
    try:
        iter(it)
        return True
    except TypeError:
        return False

>>> print recursive_join(smth=[['1','2'],['3','4'],'5'],
                     join_fnc=lambda itr: ' '.join(itr),
                     should_iter_fnc=should_iter,
                     values_fnc=list)
1 2 3 4 5
>>> print recursive_join(smth={1:{1:'1',2:'2'},2:{3:'3',4:'4'},3:'5'},
                     join_fnc=lambda itr: ' '.join(itr),
                     should_iter_fnc=should_iter,
                     values_fnc=lambda dct:dct.values())
1 2 3 4 5
0 голосов
/ 13 октября 2017

Map / Reduce является распространенным способом решения проблем такого типа.

Пример двухуровневого вложенного словаря:

>>> nested_dicts = {'one': {'one_one': 'one_one_value', 'one_two': 'one_two_value'}, 'two': {'two_one': 'two_one_value', 'two_two': 'two_two_value'}}
>>> from functools import reduce
>>> reduce(lambda x, y: x + list(y.values()), nested_dicts.values(), [])
['one_two_value', 'one_one_value', 'two_two_value', 'two_one_value']

Конечно, вы также можете использовать рекурсию с reduce:

>>> nested_dicts = {'d1': 'd1 val', 'd2': {'d2_1': {'d2_1_1': 'd2_1_1 val', 'd2_1_2': 'd2_1_2 val'}, 'd2_2': {'d2_2_1': 'd2_2_1 val'}}}
>>> def to_list(value):
...     return [value] if isinstance(value, str) else reduce(lambda x,y: x+to_list(y), value.values(), [])
... 
>>> to_list('test')
['test']
>>> reduce(lambda x, y: x+to_list(y), nested_dicts.values(), [])
['d2_2_1 val', 'd2_1_1 val', 'd2_1_2 val', 'd1 val']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...