General way to create nested dictionary from flat list in python

I am looking for the simplest general way to convert this python list:

x = [ {"foo":"A", "bar":"R", "baz":"X"}, {"foo":"A", "bar":"R", "baz":"Y"}, {"foo":"B", "bar":"S", "baz":"X"}, {"foo":"A", "bar":"S", "baz":"Y"}, {"foo":"C", "bar":"R", "baz":"Y"}, ] 

in

 foos = [ {"foo":"A", "bars":[ {"bar":"R", "bazs":[ {"baz":"X"},{"baz":"Y"} ] }, {"bar":"S", "bazs":[ {"baz":"Y"} ] }, ] }, {"foo":"B", "bars":[ {"bar":"S", "bazs":[ {"baz":"X"} ] }, ] }, {"foo":"C", "bars":[ {"bar":"R", "bazs":[ {"baz":"Y"} ] }, ] }, ] 

The combination of "foo", "bar", "baz" is unique, and as you can see, the list is not necessarily ordered using this key.

+7
source share
3 answers
 #!/usr/bin/env python3 from itertools import groupby from pprint import pprint x = [ {"foo":"A", "bar":"R", "baz":"X"}, {"foo":"A", "bar":"R", "baz":"Y"}, {"foo":"B", "bar":"S", "baz":"X"}, {"foo":"A", "bar":"S", "baz":"Y"}, {"foo":"C", "bar":"R", "baz":"Y"}, ] def fun(x, l): ks = ['foo', 'bar', 'baz'] kn = ks[l] kk = lambda i:i[kn] for k,g in groupby(sorted(x, key=kk), key=kk): kg = [dict((k,v) for k,v in i.items() if k!=kn) for i in g] d = {} d[kn] = k if l<len(ks)-1: d[ks[l+1]+'s'] = list(fun(kg, l+1)) yield d pprint(list(fun(x, 0))) 

 [{'bars': [{'bar': 'R', 'bazs': [{'baz': 'X'}, {'baz': 'Y'}]}, {'bar': 'S', 'bazs': [{'baz': 'Y'}]}], 'foo': 'A'}, {'bars': [{'bar': 'S', 'bazs': [{'baz': 'X'}]}], 'foo': 'B'}, {'bars': [{'bar': 'R', 'bazs': [{'baz': 'Y'}]}], 'foo': 'C'}] 

Note: dict is unordered! but he is the same as yours.

+3
source

I would define a function that performs one grouping step as follows:

 from itertools import groupby def group(items, key, subs_name): return [{ key: g, subs_name: [dict((k, v) for k, v in s.iteritems() if k != key) for s in sub] } for g, sub in groupby(sorted(items, key=lambda item: item[key]), lambda item: item[key])] 

and then do

 [{'foo': g['foo'], 'bars': group(g['bars'], "bar", "bazs")} for g in group(x, "foo", "bars")] 

which gives the desired result for foos .

0
source

This is a simple loop over data, without recursion. The auxiliary tree, in which the values ​​are the keys of the dictionary, is used as an index for the result tree during its construction.

 def make_tree(diclist, keylist): indexroot = {} root = {} for d in diclist: walk = indexroot parent = root for k in keylist: walk = walk.setdefault(d[k], {}) node = walk.setdefault('node', {}) if not node: node[k] = d[k] parent.setdefault(k+'s',[]).append(node) walk = walk.setdefault('children', {}) parent = node return root[keylist[0]+'s'] foos = make_tree(x, ["foo","bar","baz"]) 
0
source

All Articles