Generic way to create nested dictionary from flat list in python

后端 未结 3 1261
暗喜
暗喜 2021-01-18 04:48

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

x = [
        {\"foo\":\"A\", \"bar\":\"R\", \"baz\":\"X\"},
                 


        
相关标签:
3条回答
  • 2021-01-18 05:20

    This is a simple loop over the data, no recursion. An auxiliary tree where the values are dictionary keys is used as an index to the result tree while it is being built.

    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 讨论(0)
  • 2021-01-18 05:36

    I would define a function that performs a single grouping step like this:

    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 讨论(0)
  • 2021-01-18 05:39
    #!/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 it's the same as yours.

    0 讨论(0)
提交回复
热议问题