在python中将平面嵌套数据转换为分层数据的最佳方法

时间:2018-04-06 06:33:59

标签: python recursion nested hierarchical-data

我以平面方式表示类别层次结构 类别层次结构是

category1  
    category4
        category6  
    category5  
        category7
category2
category3

我使用字典

将其存储为列表
d = [{'id': 1, 'name': 'category1', 'parent_category_id': None, 'level': 1},
     {'id': 2, 'name': 'category2', 'parent_category_id': None, 'level': 1},
     {'id': 3, 'name': 'category3', 'parent_category_id': None, 'level': 1},
     {'id': 4, 'name': 'category4', 'parent_category_id': 1, 'level': 2},
     {'id': 5, 'name': 'category5', 'parent_category_id': 1, 'level': 2},
     {'id': 7, 'name': 'category6', 'parent_category_id': 4, 'level': 3},
     {'id': 7, 'name': 'category7', 'parent_category_id': 5, 'level': 3}]

将此类别列表转换为分层列表(如

)的最佳方法是什么
[{'name': 'category1',
  'subcategory': [{'name': 'category4',
                   'subcategory': [{'name': 'category6', 'subcategory': []}]},
                  {'name': 'category5',
                   'subcategory': [{'name': 'category7', 'subcategory': []}]}]},
 {'name': 'category2', 'subcategory': []},
 {'name': 'category3', 'subcategory': []}]

3 个答案:

答案 0 :(得分:1)

def flat_to_hierarchical(d, category_id=None):
    out = list()
    for item in filter(lambda item: item['parent_category_id']==category_id, d):
        out.append(dict(
            name = item['name'],
            subcategories = flat_to_hierarchical(d, item['id'])
        ))
    return out


print(flat_to_hierarchical(d))

答案 1 :(得分:1)

我们从[{1}}开始,给出make_treeindex节点标识

root

现在我们需要一种方法来def make_tree (index, root): if not root in index: return [] else: return [ make_node (index, child) for child in index[root] ] - 这是我们将输入数据中的元素转换为输出树元素的方法

make_node

当然,我们需要根据您的输入数据找到def make_node (index, child): return \ { 'name': child['name'] , 'children': make_tree (index, child['id']) } 的方法。我们使用itertools groupby,以便我们可以有效地查找所有子节点

make_index

最后,我们写from itertools import groupby def make_index (nodes): return \ { k: list (v) for (k,v) in groupby (nodes, lambda n: n['parent_category_id']) } 将所有内容联系起来。请注意,每次迭代都不会重新索引或过滤数据

main

完整的程序演示

def main (nodes, root = None):
  return make_tree (make_index (nodes), root)

节目输出

from itertools import groupby

def make_tree (index, root):
  if not root in index:
    return []
  else:
    return [ make_node (index, child) for child in index[root] ]

def make_node (index, child):
  return \
    { 'name': child['name']
    , 'children': make_tree (index, child['id'])
    }

def make_index (nodes):
  return \
    { k: list (v)
        for (k,v) in
          groupby (nodes, lambda n: n['parent_category_id']) }

def main (nodes, root = None):
  return make_tree (make_index (nodes), root)

d = \
  [ {'id': 1, 'name': 'category1', 'parent_category_id': None, 'level': 1}
  , {'id': 2, 'name': 'category2', 'parent_category_id': None, 'level': 1}
  , {'id': 3, 'name': 'category3', 'parent_category_id': None, 'level': 1}
  , {'id': 4, 'name': 'category4', 'parent_category_id': 1, 'level': 2}
  , {'id': 5, 'name': 'category5', 'parent_category_id': 1, 'level': 2}
  , {'id': 7, 'name': 'category6', 'parent_category_id': 4, 'level': 3}
  , {'id': 7, 'name': 'category7', 'parent_category_id': 5, 'level': 3}
  ]

# get sub-tree of [None] from dataset [d]
print (main (d, None))

答案 2 :(得分:0)

您的问题与我在Calculating the Path from Parent Child Relationships

处回答的问题非常相似

我注意到您的数据结构中似乎有很多多余的字段。基本上,您可以通过以下方式表示帖子中的信息:

d = {1: {4: {6: None}, 5: {7: None}}, 2: None, 3: None}

为您重新编写代码。

ds = [{'id': 1, 'name': 'category1', 'parent_category_id': None, 'level': 1},
     {'id': 2, 'name': 'category2', 'parent_category_id': None, 'level': 1},
     {'id': 3, 'name': 'category3', 'parent_category_id': None, 'level': 1},
     {'id': 4, 'name': 'category4', 'parent_category_id': 1, 'level': 2},
     {'id': 5, 'name': 'category5', 'parent_category_id': 1, 'level': 2},
     {'id': 6, 'name': 'category6', 'parent_category_id': 4, 'level': 3},
     {'id': 7, 'name': 'category7', 'parent_category_id': 5, 'level': 3}]

e = {1: {4: {6: None}, 5: {7: None}}, 2: None, 3: None}

parents = set()
children = {}
for d in ds:
    c = str(d['id'])
    p = str(d['parent_category_id'])
    if p is not None:
        parents.add(p)
        children[c] = p

# recursively determine parents until child has no parent
def ancestors(p):
    return (ancestors(children[p]) if p in children else []) + [p]

# for each child that has no children print the geneology
for k in (set(children.keys()) - parents):
    print ' '.join(ancestors(k)[1:])

输出:

3
2
1 5 7
1 4 6

要将其转换为嵌套字典,我建议你What is the best way to implement nested dictionaries?