How to join values โ€‹โ€‹of nested Python dictionary?

Suppose I have a dictionary and it is embedded in the dictionaries inside. I want to combine all the values โ€‹โ€‹of this dictionary, recursively?

' '.join(d.values()) 

This works if there are no sockets.

+4
source share
4 answers

The following works for any non-recursive nested dicts:

 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' 

Edit: support for recursive dicts

If you need to support self-regulatory dicts, you need to extend the above code to track all processed dicts and not try to process the dictionary that you have already seen. The following is a fairly cheap but readable way to do this:

 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' 
+7
source

Try something by

 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' 
+4
source

This will work with nested iterators of a different type than dict, if properly configured:

'Prototypes' :

 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 

Function itself

 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 

<i> gives:

 >>> 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 
+1
source

Map / Reduce is a general way to solve this problem.

Example for a two-level nested dictionary:

 >>> 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'] 

You can also use recursion with 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'] 
0
source

Source: https://habr.com/ru/post/1305431/


All Articles