【问题标题】:Converting a nested dictionary to a list将嵌套字典转换为列表
【发布时间】:2011-08-21 17:47:25
【问题描述】:

我知道这里有很多要列出问题的字典,但我找不到我需要的信息,所以我要问一个新问题。

一些背景:我正在为我的模型使用分层包,生成树结构的内置函数输出一个嵌套循环来指示父母、孩子等。我的目标是将逻辑保留在视图和输出中一个列表,这样我就可以在我的模板中简单地循环它。

这是我的数据,在树形结构中:

1
-1.1
--1.1.1
---1.1.1.1
--1.1.2
-1.2
--1.2.1
--1.2.2
-1.3

这是我得到的嵌套字典

{
 <Part: 1.1>:
 {
   <Part: 1.1.1>:
     {
       <Part: 1.1.1.1>: {}
     }, 
   <Part: 1.1.2>: {}
 },
 <Part: 1.2>: 
 {
   <Part: 1.2.1>: {},
   <Part: 1.2.2>: {}
 }, 
 <Part: 1.3>: {}
}

或者,如果您不喜欢我尝试拆分它的方式,以下是我在一行中得到的内容:

{<Part: 1.1>: {<Part: 1.1.1>: {<Part: 1.1.1.1>: {}}, <Part: 1.1.2>: {}}, <Part: 1.2>: {<Part: 1.2.1>: {}, <Part: 1.2.2>: {}}, <Part: 1.3>: {}}

我想得到的是:

[<Part: 1.1>, <Part: 1.1.1>, <Part: 1.1.1.1>, <Part: 1.1.2>, <Part: 1.2>, <Part: 1.2.2>, <Part: 1.2.1>, <Part: 1.3>,]

我尝试只迭代 dict.items 中的键,但后来我只得到顶级键 (1.1, 1.2, 1.3)

我需要做什么才能更深入?

谢谢!

【问题讨论】:

    标签: python django django-templates django-views


    【解决方案1】:

    我认为递归可以成为你的朋友:

    top = {"<Part: 1.1>": {"<Part: 1.1.1>": {"<Part: 1.1.1.1>": {}}, "<Part: 1.1.2>": {}}, "<Part: 1.2>": {"<Part: 1.2.1>": {}, "<Part: 1.2.2>": {}}, "<Part: 1.3>": {}}
    
     def grab_children(father):
        local_list = []
        for key, value in father.iteritems():
            local_list.append(key)
            local_list.extend(grab_children(value))
        return local_list
    
    print grab_children(top)
    

    【讨论】:

    • 结果错误,因为'Part: 1.3'没有出现在最后。
    【解决方案2】:

    所有以前的解决方案都递归地构建大量列表,然后将它们扩展回越来越大的列表,直到您得到最终答案。虽然它有效,但从性能角度来看并不是最佳的,因为它创建了许多您确实不需要的列表,并且涉及将相同的项目多次扩展到其父列表中。一些解决方案也忘记对键进行排序。

    top = {"<Part: 1.1>": {"<Part: 1.1.1>": {"<Part: 1.1.1.1>": {}}, "<Part: 1.1.2>": {}}, "<Part: 1.2>": {"<Part: 1.2.1>": {}, "<Part: 1.2.2>": {}}, "<Part: 1.3>": {}}
    
    def flatten(d, ret=None):
        if ret is None:
            ret = []
        for k, v in sorted(d.items()):
            ret.append(k)
            if v:
                flatten(v, ret)
        return ret
    
    def test():
        flatten(top)
    

    根据python -m timeit -s "import flatten" "flatten.test()",此方法每个循环使用 8.57 微秒,而 Cédrics 答案的每个循环使用 14.4 微秒,更新后也可以正确排序输出 (for key, value in sorted(father.items()):)

    【讨论】:

      【解决方案3】:

      Inception...呃,我的意思是,递归。试试这个:

      def recurse(dict):
          result = []
          for key in dict:
              result.append(key)
              result.extend(recurse(dict[key]))
          return result
      

      【讨论】:

      • 我在 shell 中做了这个,它返回了几百个值而不是 10 个?我错过了什么吗?
      • 结果错误,因为'Part: 1.3'没有出现在最后。
      • 它执行的次数越多,它就会不断地添加自己。
      • 它对我来说很好用。也许您不小心将result 声明为全局变量?
      • 我不知道我第一次做了什么,但它确实工作得很好
      【解决方案4】:

      根据米海的回答:你需要对你的钥匙进行排序,否则你可能会遇到问题:

      def recurse(d):
          result = []
          for key in sorted(d.keys()):
              result.append(key)
              result.extend(recurse(d[key]))
          return result
      

      【讨论】:

      • 的第 5 行得到一个 KeyError
      【解决方案5】:

      这个问题不能通过对字典的简单迭代来解决。你需要一种叫做recursive descent的算法

      def getKeys(D, answer):
          if not D:
              return
          else:
              for k in D:
                  answer.append(k)
                  getKeys(D[k], answer)
      
      if __name__ == "__main__":
          d = {"<Part: 1.1>": {"<Part: 1.1.1>": {"<Part: 1.1.1.1>": {}}, "<Part: 1.1.2>": {}}, "<Part: 1.2>": {"<Part: 1.2.1>": {}, "<Part: 1.2.2>": {}}, "<Part: 1.3>": {}}
          answer = []
          getKeys(d, answer)
          print answer
      

      这已经过测试并且正在工作

      希望对你有帮助

      【讨论】:

      • for 循环只会进行一次迭代,因为它包含一个returnmodifying a default argument 也不是一个好主意...
      • 是的,回归并不是有史以来最好的举动。不过现在已经修好了
      猜你喜欢
      • 2020-09-03
      • 1970-01-01
      • 1970-01-01
      • 2022-12-05
      • 2017-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多