【问题标题】:Providing an id for each recursed item in nested dictionary of lists of dictionaries为字典列表的嵌套字典中的每个递归项提供一个 id
【发布时间】:2012-09-26 12:21:39
【问题描述】:

扩展名:recursing a dictionary of lists of dictionaries, etc et al (python)

我正在使用 4 个级别的嵌套字典结构,我正在尝试迭代整个嵌套字典并为每个单独的字典提供一个标识号(作为构建项目树并能够分辨的前兆哪个项目节点是父节点,节点有哪些子节点等)

我有这个功能:

def r(y):
    cnt = 1
    def recurse(y, count):
        for i in y.iteritems():
            count+=1
            i['id'] = count
            for k,v in y.iteritems():
                if isinstance(v, list):
                    [recurse(i, count) for i in v]
                else:
                    pass
    recurse(y, cnt)
    return y

我把字典列表的嵌套字典放进去,

我弄得一团糟,即没有像我想象的那样工作。

{'sections': [{'id': 11, 'info': 'This is section ONE', 'tag': 's1'},
              {'fields': [{'id': 15,
                           'info': 'This is field ONE',
                           'tag': 'f1'},
                          {'elements': [{'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e1',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e2',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e3',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e4',
                                         'type_of': 'text_field'}],
                           'id': 16,
                           'info': 'This is field TWO',
                           'tag': 'f2'},
                          {'elements': [{'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e5',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e6',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e7',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element ONE',
                                         'tag': 'e8',
                                         'type_of': 'text_field'}],
                           'id': 16,
                           'info': 'This is field THREE',
                           'tag': 'f3'}],
               'id': 12,
               'info': 'This is section TWO',
               'tag': 's2'},
              {'fields': [{'id': 15,
                           'info': 'This is field FOUR',
                           'tag': 'f4'},
                          {'id': 15,
                           'info': 'This is field FIVE',
                           'tag': 'f5'},
                          {'id': 15,
                           'info': 'This is field SIX',
                           'tag': 'f6'}],
               'id': 12,
               'info': 'This is section THREE',
               'tag': 's3'}],
 'tag': 'test'}

我想要发生的是,第一级的所有项目都被编号,然后第二级的所有项目都被编号,然后是第三级,然后是第四级。在这种情况下,主要项目的 id 应为 1,然后将部分标识为 2、3、4,然后将字段标识为 5,然后是元素等。在睡觉后回头看,我可以将其视为开始,但完全错误。

编辑:我真正需要做的是从嵌套字典结构创建父/子节点树,以便我可以根据需要迭代/插入/获取/使用该树中的项目。有没有快速的方法来做到这一点?我的工作似乎比我预期的要多。

EDIT2:我找到了original question 的解决方案。我只是决定使用内置的 id() 函数而不是添加 id 的额外步骤,并且能够创建我需要的最小树,但这仍然是一个有用的练习。

【问题讨论】:

  • 在最初的问题中,有人问你想要什么输出,你说你想“编辑东西”。在这里,您需要“父/子节点树”,但树不是具体的数据结构。您的原始数据已经是作为字典列表实现的父/子节点树 - 您是否想要具有更少字段的相同列表结构,或者您是否希望您的树成为列表列表,或者你想要一个扁平的轮廓:(1 a,1.1 b,1.1.1 c,1.2 d,...)?请从给定的输入中发布您想要的输出。
  • 嗯,这是对我想要完成的目标不断发展的理解。我有4个数据库模型A,B,C,D。B属于A,C属于B等。我需要通过这个嵌套结构创建A,然后创建B并添加到A,然后创建C并添加到相应的B等等等等。我需要遍历该结构并将每个节点及其与父/子的关系隔离在一个临时结构中,我可以引用该结构以分层方式说“创建这个对象,附加这个另一个对象”。而且我还没有找到一种简单的方法,也许对其他人来说很明显,但我只是在尝试不同的方法。

标签: python dictionary tree loops


【解决方案1】:

您会得到重复的 id,因为您的 count 变量是本地变量,并且一旦 recurse 函数退出,对它的任何更改都会丢失。你可以通过声明一个全局变量来绕过它,但是由于你没有使用recurse的返回值,你可以使用它来代替:

def r(y):
    def recurse(y, count):
        y['id'] = count
        count += 1
        for k,v in y.iteritems():
            if isinstance(v, list):
                for i in v:
                    count = recurse(i, count)
        return count
    recurse(y, 1)
    return y

编辑:刚刚意识到您正在寻找 id 的广度优先分配...这不会实现这一点,但我会留下答案,因为它可能有助于您入门。

【讨论】:

    【解决方案2】:

    嗯,我有一个使用深度和父级来设置 ID 的解决方案:

    >>> def decorate_tree(tree, parent=None, index=None):
        global ID
        if type(tree) == type({}):
            if parent is None:
                parent = '1'
                tree['id'] = parent
            else:
                tree['id'] = '{0}.{1}'.format(parent, index)
            if 'info' in tree:
                print tree['info'], '=>', tree['id']
            child_index = 1
            for key in tree:
                if type(tree[key]) == type([]):
                    for item in tree[key]:
                        decorate_tree(item, tree['id'], child_index)
                        child_index += 1
    
    
    >>> decorate_tree(d)
    This is section ONE => 1.1
    This is section TWO => 1.2
    This is field ONE => 1.2.1
    This is field TWO => 1.2.2
    This is element => 1.2.2.1
    This is element => 1.2.2.2
    This is element => 1.2.2.3
    This is element => 1.2.2.4
    This is field THREE => 1.2.3
    This is element => 1.2.3.1
    This is element => 1.2.3.2
    This is element => 1.2.3.3
    This is element ONE => 1.2.3.4
    This is section THREE => 1.3
    This is field FOUR => 1.3.1
    This is field FIVE => 1.3.2
    This is field SIX => 1.3.3
    >>> from pprint import pprint
    >>> pprint(d)
    {'id': '1',
     'sections': [{'id': '1.1', 'info': 'This is section ONE', 'tag': 's1'},
                  {'fields': [{'id': '1.2.1',
                               'info': 'This is field ONE',
                               'tag': 'f1'},
                              {'elements': [{'id': '1.2.2.1',
                                             'info': 'This is element',
                                             'tag': 'e1',
                                             'type_of': 'text_field'},
                                            {'id': '1.2.2.2',
                                             'info': 'This is element',
                                             'tag': 'e2',
                                             'type_of': 'text_field'},
                                            {'id': '1.2.2.3',
                                             'info': 'This is element',
                                             'tag': 'e3',
                                             'type_of': 'text_field'},
                                            {'id': '1.2.2.4',
                                             'info': 'This is element',
                                             'tag': 'e4',
                                             'type_of': 'text_field'}],
                               'id': '1.2.2',
                               'info': 'This is field TWO',
                               'tag': 'f2'},
                              {'elements': [{'id': '1.2.3.1',
                                             'info': 'This is element',
                                             'tag': 'e5',
                                             'type_of': 'text_field'},
                                            {'id': '1.2.3.2',
                                             'info': 'This is element',
                                             'tag': 'e6',
                                             'type_of': 'text_field'},
                                            {'id': '1.2.3.3',
                                             'info': 'This is element',
                                             'tag': 'e7',
                                             'type_of': 'text_field'},
                                            {'id': '1.2.3.4',
                                             'info': 'This is element ONE',
                                             'tag': 'e8',
                                             'type_of': 'text_field'}],
                               'id': '1.2.3',
                               'info': 'This is field THREE',
                               'tag': 'f3'}],
                   'id': '1.2',
                   'info': 'This is section TWO',
                   'tag': 's2'},
                  {'fields': [{'id': '1.3.1',
                               'info': 'This is field FOUR',
                               'tag': 'f4'},
                              {'id': '1.3.2',
                               'info': 'This is field FIVE',
                               'tag': 'f5'},
                              {'id': '1.3.3',
                               'info': 'This is field SIX',
                               'tag': 'f6'}],
                   'id': '1.3',
                   'info': 'This is section THREE',
                   'tag': 's3'}],
     'tag': 'test',
     'type_of': 'custom'}
    >>> 
    

    所以 ID 1.3.4 的父级是 ID 1.3,兄弟级是 ID 1.3.x,子级是 1.3.4.x...这样检索和插入应该不会太难(移位索引)。

    【讨论】:

      【解决方案3】:

      这是一个用itertools.count 迭代器替换您的count 变量的解决方案:

      from itertools import count
      def r(y):
          counter = count()
          def recurse(y, counter):
              for i in y.iteritems():
                  i['id'] = next(counter)
                  for k,v in y.iteritems():
                      if isinstance(v, list):
                          [recurse(i, counter) for i in v]
                      else:
                          pass
          recurse(y, counter)
          return y
      

      itertools.count() 将创建一个生成器,该生成器将在每次调用 next() 时返回下一个整数。您可以将其传递给递归函数,并确保不会创建重复的 id。

      【讨论】:

        【解决方案4】:

        要考虑的替代方法是双向链表。例如:

        Index  Tag     Parent  Children        Info
        0      test    -1      [s1,s2,s3]      ""
        1      s1      0       []              "This is section ONE"
        2      s2      0       [f1,f2,f3]      "This is section TWO"
        3      f1      2       []              "This is field ONE"
        4      f2      2       [e1,e2,e3,e4]   "This is field TWO"
        5      e1      4       []              "This is element"
        6      e2      4       []              "This is element"
               .
               .
               .
        

        这是一个概念表示,实际实现将使用子列的数字行索引而不是标签,因为您的输入数据可能是脏的,带有重复或缺失的标签,并且您不想构建一个结构取决于标签是唯一的。可以轻松添加其他列。

        您可以通过递归遍历树来构建表,但使用平面表(列表的二维列表)中的行来引用它们可能更容易处理树中的项目。

        编辑:这是您对原始问题(未修饰的节点列表)的解决方案的扩展,它将结构化信息(标签、父级、子级等)添加到每个节点。如果您需要在树上上下导航,这可能会很有用。

        编辑:这段代码:

        def recurse(y, n=[], p=-1):
            node = ["", p, [], "", ""]   # tag, parent, children, type, info
            vv = []
            for k,v in y.items():
                if k == "tag":
                    node[0] = v
                elif k == "info":
                    node[4] = v
                elif isinstance(v, list):
                    node[3] = k
                    vv = v
            n.append(node)
            p = len(n)-1
            for i in vv:
                n[p][2].append(len(n))
                n = recurse(i, n, p)
            return(n)
        
        nodes = recurse(a)
        for i in range(len(nodes)):
            print(i, nodes[i])
        

        产生(为了便于阅读,手动分隔成列):

         0 ['test', -1, [1, 2, 14],     'sections',   '']
         1 [  's1',  0, [],             '',           'This is section ONE']
         2 [  's2',  0, [3, 4, 9],      'fields',     'This is section TWO']
         3 [  'f1',  2, [],             '',           'This is field ONE']
         4 [  'f2',  2, [5, 6, 7, 8],   'elements',   'This is field TWO']
         5 [  'e1',  4, [],             '',           'This is element']
         6 [  'e2',  4, [],             '',           'This is element']
         7 [  'e3',  4, [],             '',           'This is element']
         8 [  'e4',  4, [],             '',           'This is element']
         9 [  'f3',  2, [10, 11, 12, 13], 'elements', 'This is field THREE']
        10 [  'e5',  9, [],             '',           'This is element']
        11 [  'e6',  9, [],             '',           'This is element']
        12 [  'e7',  9, [],             '',           'This is element']
        13 [  'e8',  9, [],             '',           'This is element ONE']
        14 [  's3',  0, [15, 16, 17],   'fields',     'This is section THREE']
        15 [  'f4', 14, [],             '',           'This is field FOUR']
        16 [  'f5', 14, [],             '',           'This is field FIVE']
        17 [  'f6', 14, [],             '',           'This is field SIX']
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-06-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-08
          • 2021-11-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多