【问题标题】:Generate a nested list from flatten data in Python从 Python 中的展平数据生成嵌套列表
【发布时间】:2011-03-09 00:55:56
【问题描述】:

为了生成目录,我在 Python 列表中提供了这些数据:

data = [
    {title: 'Section 1', level: 1, page_number: 1},
    {title: 'Section 1.1', level: 2, page_number: 2},
    {title: 'Section 1.2', level: 2, page_number: 3},
    {title: 'Section 2', level: 1, page_number: 4},
    {title: 'Section 2.1', level: 2, page_number: 5},
    {title: 'Section 3', level: 1, page_number: 6},
]

由此,我想获得这种嵌套结构,更兼容模板引擎的使用:

toc = [
    {title: 'Section 1', page_number: 1, sub: [
        {title: 'Section 1.1', page_number: 2, sub: []},
        {title: 'Section 1.2', page_number: 3, sub: []},
    ]},
    {title: 'Section 2', page_number: 4, sub: [
        {title: 'Section 2.1', page_number: 5, sub: []},    
    ]},
    {title: 'Section 3', page_number: 6, sub: []},
]

关于如何实现这一点的提示?我尝试使用递归函数,但对于我有限的大脑来说它变得非常棘手。

非常感谢任何帮助。

编辑:添加了一个部分条目最终可以没有子项的事实。很抱歉错过了。

【问题讨论】:

  • 不需要递归,循环和栈一样的列表结构也可以工作。

标签: python list recursion tree


【解决方案1】:

假设章节是按顺序排列的,这意味着子章节总是在父章节之后,并且没有缺少父章节(跳过级别):

import pprint

data = [
    {'title': 'Section 1', 'level': 1, 'page_number': 1},
    {'title': 'Section 1.1', 'level': 2, 'page_number': 2},
    {'title': 'Section 1.2', 'level': 2, 'page_number': 3},
    {'title': 'Section 2', 'level': 1, 'page_number': 4},
    {'title': 'Section 2.1', 'level': 2, 'page_number': 42},
    {'title': 'Section 2.1.1', 'level': 3, 'page_number': 42},
    {'title': 'Section 3', 'level': 1, 'page_number': 42},
]

toc = []
stack = [toc]
for d in data:
    d['sub'] = []   
    while d['level'] < len(stack):
        stack.pop()
    while d['level']  > len(stack):
        stack.append(stack[-1][-1]['sub'])
    stack[-1].append(d)


pprint.pprint(toc)

结果:

[{'level': 1,
  'page_number': 1,
  'sub': [{'level': 2, 'page_number': 2, 'sub': [], 'title': 'Section 1.1'},
          {'level': 2, 'page_number': 3, 'sub': [], 'title': 'Section 1.2'}],
  'title': 'Section 1'},
 {'level': 1,
  'page_number': 4,
  'sub': [{'level': 2,
           'page_number': 42,
           'sub': [{'level': 3,
                    'page_number': 42,
                    'sub': [],
                    'title': 'Section 2.1.1'}],
           'title': 'Section 2.1'}],
  'title': 'Section 2'},
 {'level': 1, 'page_number': 42, 'sub': [], 'title': 'Section 3'}]

编辑:将其更改为没有子项的空“子”项。查看编辑历史记录中的其他变体。

【讨论】:

  • 啊,我应该在声明中指定section也不能有子...但是这里的东西很棒,值得深思
  • 嘿,你的速度很快。好的,它现在按预期工作,非常感谢:)
  • @NiKo 不同之处不在于一个部分可以没有子项(这很清楚),而是在这种情况下您想要一个空的“子”条目。我的第一个代码没有放空的“子”,这个有。
【解决方案2】:

您可以遍历列表中的每个条目并从那里构建一个新列表。每当有“Section x.y”时,您都会将其添加到 sub 下。

newData = []
curParent = None
for d in data:
  # child
  if d['title'].find('.') > 0:
    assert curParent # Make sure we have a valid parent dictionary
    curParent['sub'].append({'title': d['title'], 'page_number': d['page_number'])
  # parent
  else:
    curParent = {'title': d['title'], 'page_number': d['page_number'], 'sub': []}
    newData.append(curParent)

这应该适用于 2 或 3 个级别,如果您需要更多,那么不同的方法可能会更好。此外,find('.') 可能不适用于其他标题,但可以使用级别字段(在您的示例中似乎是多余的)或正则表达式。

【讨论】:

  • 是的,我可以有很多嵌套级别。另外,我真的不想依赖部分标题中存在的点;)
  • 对每个不完美的答案都投反对票并不是很好。不是我故意写错,只是另一种方法而已。
【解决方案3】:

这是你想要的吗?

TITLE, LEVEL, PAGE_NUMBER, SUB = 'title', 'level', 'page_number', 'sub'
data = [
    {TITLE: 'Section 1', LEVEL: 1, PAGE_NUMBER: 1},
    {TITLE: 'Section 1.1', LEVEL: 2, PAGE_NUMBER: 2},
    {TITLE: 'Section 1.1.1', LEVEL: 3, PAGE_NUMBER: 2},
    {TITLE: 'Section 1.2', LEVEL: 2, PAGE_NUMBER: 3},
    {TITLE: 'Section 2', LEVEL: 1, PAGE_NUMBER: 4},
    {TITLE: 'Section 2.1', LEVEL: 2, PAGE_NUMBER: 5},
]

levels = [ { SUB: [] } ]
for section in data:
    section = dict(section)
    current = section[LEVEL]
    section[SUB] = []
    levels[current-1][SUB].append(section)
    del levels[current:]
    levels.append(section)

toc = levels[0][SUB]
from pprint import pprint
pprint(toc)

【讨论】:

  • 还是一个栈,只是看着略有不同。我认为主要区别在于您仅将子列表保存在我保存整个部分的每个级别中。这是否重要可能是一个有趣的问题。
猜你喜欢
  • 1970-01-01
  • 2012-07-07
  • 2017-05-08
  • 2018-07-04
  • 2015-04-13
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多