简体   繁体   English

来自python元组的多嵌套字典

[英]multi nested dictionary from tuples in python

I have this list of tuples 我有这个元组列表

list_of_tuples = [('0', '1'), ('1', '1.1'), ('1', '1.2'), ('1', '1.3'), ('1', '1.4'), ('0', '3'), ('3', '3.1'), ('3', '3.2'), ('3', '3.3'), ('3', '3.4'), ('3', '3.5'), ('0', '4'), ('4', '4.1'), ('4', '4.2'), ('4', '4.3'), ('4', '4.4'), ('4', '4.5'), ('4', '4.6'), ('4', '4.7'), ('4', '4.8'), ('4', '4.9'), ('0', '5'), ('5', '5.1'), ('5', '5.2'), ('5', '5.3'), ('5', '5.4'), ('0', '6'), ('6', '6.1'), ('6', '6.2'), ('6', '6.3'), ('6', '6.4'), ('6', '6.5'), ('0', '7'), ('7', '7.1'), ('7', '7.2'), ('7', '7.3'), ('7.3', '7.3.1'), ('7.3', '7.3.2'), ('7.3', '7.3.3'), ('0', '8'), ('8', '8.1.1'), ('8', '8.1.2'), ('8', '8.2'), ('0', '9'), ('9', '9.1'), ('9', '9.2'), ('0', '10'), ('10', '10.1'), ('10', '10.2'), ('10', '10.3'), ('10.3', '10.3.2'), ('10.3', '10.3.3'), ('10.3', '10.3.4'), ('10.3', '10.3.5'), ('10.3', '10.3.6')

The first value in the tuple is the parent and the second is the value. 元组中的第一个值是父级,第二个是值。

(parent,child)

i want the output to be like this. 我希望输出是这样的。

{ '0':
     {'1':
         {'1.1':None,
          '1.2':None......
         }
     {'3':
         {'3.1':None/[]..
         }
     }
}

i can add it to the dictionary but i want it to be nested like a tree with multiple children. 我可以将其添加到字典中,但我希望它像一棵有多个孩子的树一样嵌套。

d = defaultdict(list)
for k, v in h:
   d[k].append(v)

Any help is appreciated. 任何帮助表示赞赏。

I'm going to whip up a quick tree class that can take this input and build a tree with it, then I'm going to write a method for that class that converts them back to dictionaries 我将准备一个快速的树类,该树可以接受此输入并用它构建树,然后为该类编写一个将其转换回字典的方法

class Tree:
    def __init__(self, name, parent=None): #parent is None to detect root
        self.name = name
        self.parent = parent
        self.children = []    
    def add(self, target , child):
        '''
        Does DFS until it finds Tree with name target.  Creates a Tree(child)
        as child of Tree name
        '''
        if self.name == target:
            self.children.append(Tree(child, self))
            return True
        else:
            for subtree in self.children:
                if subtree.add(target, child):
                    return True
        if self.parent:
            return False
        raise ValueError('Bad Parent no such node {}'.format(target))    
    def dictify(self):
        d = {}
        for child in self.children:
          d.update(child.dictify())
        return {self.name: d}

list_of_tuples = [('0', '1'), ('1', '1.1'), ('1', '1.2'), ('1', '1.3'), ('1', '1.4'), ('0', '3'), ('3', '3.1'), ('3', '3.2'), ('3', '3.3'), ('3', '3.4'), ('3', '3.5'), ('0', '4'), ('4', '4.1'), ('4', '4.2'), ('4', '4.3'), ('4', '4.4'), ('4', '4.5'), ('4', '4.6'), ('4', '4.7'), ('4', '4.8'), ('4', '4.9'), ('0', '5'), ('5', '5.1'), ('5', '5.2'), ('5', '5.3'), ('5', '5.4'), ('0', '6'), ('6', '6.1'), ('6', '6.2'), ('6', '6.3'), ('6', '6.4'), ('6', '6.5'), ('0', '7'), ('7', '7.1'), ('7', '7.2'), ('7', '7.3'), ('7.3', '7.3.1'), ('7.3', '7.3.2'), ('7.3', '7.3.3'), ('0', '8'), ('8', '8.1.1'), ('8', '8.1.2'), ('8', '8.2'), ('0', '9'), ('9', '9.1'), ('9', '9.2'), ('0', '10'), ('10', '10.1'), ('10', '10.2'), ('10', '10.3'), ('10.3', '10.3.2'), ('10.3', '10.3.3'), ('10.3', '10.3.4'), ('10.3', '10.3.5'), ('10.3', '10.3.6')]

root = Tree('0')
for parent, child in list_of_tuples:
  root.add(parent, child)
print(root.dictify())

Here is is with pprint (pretty printing) 这是pprint (漂亮的打印)

{'0': {'1': {'1.1': {}, '1.2': {}, '1.3': {}, '1.4': {}},
       '10': {'10.1': {},
              '10.2': {},
              '10.3': {'10.3.2': {},
                       '10.3.3': {},
                       '10.3.4': {},
                       '10.3.5': {},
                       '10.3.6': {}}},
       '3': {'3.1': {}, '3.2': {}, '3.3': {}, '3.4': {}, '3.5': {}},
       '4': {'4.1': {},
             '4.2': {},
             '4.3': {},
             '4.4': {},
             '4.5': {},
             '4.6': {},
             '4.7': {},
             '4.8': {},
             '4.9': {}},
       '5': {'5.1': {}, '5.2': {}, '5.3': {}, '5.4': {}},
       '6': {'6.1': {}, '6.2': {}, '6.3': {}, '6.4': {}, '6.5': {}},
       '7': {'7.1': {},
             '7.2': {},
             '7.3': {'7.3.1': {}, '7.3.2': {}, '7.3.3': {}}},
       '8': {'8.1.1': {}, '8.1.2': {}, '8.2': {}},
       '9': {'9.1': {}, '9.2': {}}}}

If you want those empty dicts to be None just change dictify to return {self.name: d if d else None} 如果您希望这些空的dictifyNone只需更改dictifyreturn {self.name: d if d else None}

Edit: schwobaseggl makes a good point about insertion complexity. 编辑:schwobaseggl很好地指出了插入的复杂性。 Here is a version of the Tree class that takes advantage of ordered inputs 这是使用有序输入的Tree类的版本

class Tree:
    def __init__(self, name, parent=None): #parent is None to detect root
        self.name = name
        self.parent = parent
        self.children = []        
    def add(self, target , child):
        '''
        Accepts additions in DFS order.  Relies on the fact that every node will
        be the direct descendant of the previous node or one of its ancestors.
        '''
        if self.name == target:
            kiddo = Tree(child, self)
            self.children.append(kiddo)
            return kiddo
        elif self.parent:
            return self.parent.add(target, child)
        else:
            raise ValueError('Bad Parent no such node {}'.format(target))    
    def dictify(self):
        d = {}
        for child in self.children:
          d.update(child.dictify())
        return {self.name: d}
list_of_tuples = [('0', '1'), ('1', '1.1'), ('1', '1.2'), ('1', '1.3'), ('1', '1.4'), ('0', '3'), ('3', '3.1'), ('3', '3.2'), ('3', '3.3'), ('3', '3.4'), ('3', '3.5'), ('0', '4'), ('4', '4.1'), ('4', '4.2'), ('4', '4.3'), ('4', '4.4'), ('4', '4.5'), ('4', '4.6'), ('4', '4.7'), ('4', '4.8'), ('4', '4.9'), ('0', '5'), ('5', '5.1'), ('5', '5.2'), ('5', '5.3'), ('5', '5.4'), ('0', '6'), ('6', '6.1'), ('6', '6.2'), ('6', '6.3'), ('6', '6.4'), ('6', '6.5'), ('0', '7'), ('7', '7.1'), ('7', '7.2'), ('7', '7.3'), ('7.3', '7.3.1'), ('7.3', '7.3.2'), ('7.3', '7.3.3'), ('0', '8'), ('8', '8.1.1'), ('8', '8.1.2'), ('8', '8.2'), ('0', '9'), ('9', '9.1'), ('9', '9.2'), ('0', '10'), ('10', '10.1'), ('10', '10.2'), ('10', '10.3'), ('10.3', '10.3.2'), ('10.3', '10.3.3'), ('10.3', '10.3.4'), ('10.3', '10.3.5'), ('10.3', '10.3.6')]

root = Tree('0')
curr = root
for parent, child in list_of_tuples:
  curr = curr.add(parent, child)
print(root.dictify())

Patrick's solution is generic and object-oriented. Patrick的解决方案是通用且面向对象的。 However, it is O(N^2) ( N being the number of edges) because it traverses the entire tree for each edge. 但是,它是O(N^2)N是边的数量),因为它遍历每个边的整个树。 Since you know that you get the edges in depth-first order, you can save a lot (for large trees: a lot lot!) of time by memorizing your current position in the tree, inserting right where you are, and going back up the tree if needed. 既然您知道边缘是按深度优先的顺序排列的,那么您可以通过记住树中的当前位置,插入到当前位置然后返回来节省很多时间(对于大树:很多!)如果需要的话。

The following is more concise and O(N) without the additional overhead of your own classes and extra-conversion: 以下内容更加简洁明了,并且O(N)却没有您自己的类的额外开销和额外的转换:

from pprint import pprint

d = {}
crnt = d  # memo the crnt subtree
stck = []  # stack of (sub)trees along current path
for k, v in list_of_tuples:
  while stck and k not in crnt:
    crnt = stck.pop()
  if k not in crnt:
    crnt[k] = {}
  stck.append(crnt)
  crnt = crnt[k]
  crnt[v] = {}

pprint(d)

{'0': {'1': {'1.1': {}, '1.2': {}, '1.3': {}, '1.4': {}},
       '10': {'10.1': {},
              '10.2': {},
              '10.3': {'10.3.2': {},
                       '10.3.3': {},
                       '10.3.4': {},
                       '10.3.5': {},
                       '10.3.6': {}}},
       '3': {'3.1': {}, '3.2': {}, '3.3': {}, '3.4': {}, '3.5': {}},
       '4': {'4.1': {},
             '4.2': {},
             '4.3': {},
             '4.4': {},
             '4.5': {},
             '4.6': {},
             '4.7': {},
             '4.8': {},
             '4.9': {}},
       '5': {'5.1': {}, '5.2': {}, '5.3': {}, '5.4': {}},
       '6': {'6.1': {}, '6.2': {}, '6.3': {}, '6.4': {}, '6.5': {}},
       '7': {'7.1': {},
             '7.2': {},
             '7.3': {'7.3.1': {}, '7.3.2': {}, '7.3.3': {}}},
       '8': {'8.1.1': {}, '8.1.2': {}, '8.2': {}},
       '9': {'9.1': {}, '9.2': {}}}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM