2012-01-03 45 views
7

Tôi đang tìm kiếm đơn giản nhất generic cách để chuyển đổi danh sách python này:cách Generic để tạo từ điển lồng nhau từ danh sách phẳng trong python

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"}, 
    ] 

thành:

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"} ] }, 
          ] 
     }, 
     ] 

Sự kết hợp "foo "," bar "," baz "là duy nhất và bạn có thể thấy danh sách không nhất thiết phải được sắp xếp theo khóa này.

+6

Cách của bạn (không nhất thiết là cách đơn giản nhất, nhưng bạn) để thực hiện? – eumiro

Trả lời

3
#!/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'}] 

lưu ý: dict là không có thứ tự! nhưng nó giống như của bạn.

0

tôi sẽ xác định một hàm thực hiện một bước nhóm đơn như thế này:

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

và sau đó làm

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

mang đến cho kết quả mong muốn cho foos.

0

Đây là vòng lặp đơn giản trên dữ liệu, không có đệ quy. Một cây phụ trợ, nơi các giá trị là các khóa từ điển được sử dụng như một chỉ mục cho cây kết quả trong khi nó đang được xây dựng.

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"]) 
Các vấn đề liên quan