Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在另一个嵌套的dict列表中添加dict列表并检查父项_Python_List_Dictionary_Yaml - Fatal编程技术网

Python 在另一个嵌套的dict列表中添加dict列表并检查父项

Python 在另一个嵌套的dict列表中添加dict列表并检查父项,python,list,dictionary,yaml,Python,List,Dictionary,Yaml,我试图在dict的嵌套列表中追加dict,同时检查相同的父项,然后在适当的位置追加。例如,我的输入dicts和所需输出为: 输入: Dict1 = [{'name':'A', 'childs':[{ 'name':'B', 'childs':[{ 'name':'C', 'childs':[{

我试图在dict的嵌套列表中追加dict,同时检查相同的父项,然后在适当的位置追加。例如,我的输入
dicts
和所需输出为:

输入

Dict1 = [{'name':'A', 
          'childs':[{
                'name':'B', 
                'childs':[{
                      'name':'C',
                       'childs':[{
                             'name':'D', 
                             'childs': None}]}]}]},
          {'name':'E', 'childs':None}]
Dict2=[{'name':'B',
        'childs':[{
              'name':'C',
              'childs':[{
                    'name':'X', 
                    'childs':None}]}]}]
输出:-

Dict1 = [{'name':'A', 
          'childs':[{
                'name':'B', 
                'childs':[{
                      'name':'C',
                       'childs':[{
                             'name':'D', 
                             'childs': None},
                            {'name':'X' , 
                             'childs':None}}]}]},
          {'name':'E' , 'childs':None}]
它只是将一个字典作为另一个字典的子字典进行附加,但我无法弄清楚,在两个字典中迭代时,如何检查相同的父字典,然后进行附加

def get_dict_with_name(name, list_of_dicts):
     ''' 
     returns the dict that has the same name as name from list_of_dicts
     assured a dict or None
     '''
     if not list_of_dicts:
         return None

     for _dict in list_of_dicts:
         if name == _dict['name']:
             return _dict
         # check children as well
         dict_from_children = get_dict_with_name(name, _dict['childs'])
         if dict_from_children:
             return dict_from_children

     return None

 def append_stuff(list_of_dicts_1, list_of_dict_2):
     ''' 
     iter through all of list_of_dict_2, and merge with 1
     '''
     if not list_of_dict_2:
         return
     if not list_of_dicts_1:
         return

     for _dict in list_of_dict_2:
         name = _dict['name']
         dict_in_1 = get_dict_with_name(name, list_of_dicts_1)
         # if u dont get a dict, simply add it as a new dict to the list
         if not dict_in_1:
             list_of_dicts_1.append(_dict)
             continue

         # if you found, now check with children - each of these children in that dict
         append_stuff(dict_in_1['childs'], _dict['childs'])
它将其添加到目录1的列表中。应该这样做。 然而,由于它具有这种层次结构,也许构建一个树结构对您更有用

在您的输入中,您调用了两个列表Dict1和Dict2 所以在这里,您称为append_stuff(Dict1,Dict2) 并且Dict1具有所需的输出。

1。方法说明 我提出以下方法:

  • gen_base
    从包含孩子和父母的给定词典列表生成数据库。数据库是一个字典,有助于不同元素的索引化。它包含诸如
    {…,'B':{'childs':['C'],'parent':'A'},}
  • build_tree
    创建一个方法,该方法使用生成的数据库构建给定名称的树
  • merge\u from\u base
    合并数据库元素以形成完整的树
方法如下:

2.执行示例 让
Dict1
Dict2
成为您作为示例给出的词典列表和
Dict3
所需结果

>>> base = gen_base(Dict1 + Dict2)
>>> base
{'A': {'childs': ['B'], 'parent': None},
 'B': {'childs': ['C'], 'parent': 'A'},
 'C': {'childs': ['D', 'X'], 'parent': 'B'},
 'D': {'childs': [], 'parent': 'C'},
 'E': {'childs': [], 'parent': None},
 'X': {'childs': [], 'parent': 'C'}}

>>> res = merge_from_base(base=base,)
>>> res
[{'name': 'A', 'childs': [
    {'name': 'B', 'childs': [
        {'name': 'C', 'childs': [
            {'name': 'D', 'childs': None,},
            {'name': 'X', 'childs': None,}],}],}],},
 {'name': 'E', 'childs': None,}]

>>> res == Dict3
True
3.来源
认真地说,Taha,

这是一个稍微修改的节点类,用于构建相同的结构。我觉得这里的核心逻辑更容易理解

$> cat input.txt ( From your sample input )
{'d2': [{'childs': [{'childs': [{'childs': None, 'name': 'X'}], 'name': 'C'}], 'name': 'B'}], 'd1': [{'childs': [{'childs': [{'childs': [{'childs': None, 'name': 'D'}], 'name': 'C'}], 'name': 'B'}], 'name': 'A'}, {'childs': None, 'name': 'E'}]}

$>vi test1.py (sorry for the name, your question was too long)
class Node(object):
    def __init__(self, name):
    ''' not making children None, [] is easier to work with '''
        self.name = name
        self.children = []

    def add_child(self, child):
        self.children.append(child)

    def flatten_to_dict(self):
        ''' to get it back to your format '''
        my_dict = {'name': self.name, 'childs': []}

        for child in self.children:
            my_dict['childs'].append(child.flatten_to_dict())

        return my_dict

    @staticmethod
    def from_dict(inp_dict):
        ''' taking the input as dictionaries - your format converter '''
        root = Node(inp_dict['name'])
        if not inp_dict['childs']:
            return root

        for child in inp_dict['childs']:
            root.add_child(Node.from_dict(child))
        return root

    def __repr__(self):
        ''' u know what this is for '''
        return "%s" % self.flatten_to_dict()

    def find_node_with_name(self, name):
        if self.name == name:
            return self

        for child in self.children:
            found_node = child.find_node_with_name(name)
            if found_node:
                return found_node
        return None

    @staticmethod
    def merge_nodes(node1, node2):
        ''' the actual core logic, very simple '''
        the_node = node1.find_node_with_name(node2.name)

        if not the_node:
            return None

        for child in node2.children:
            n = Node.merge_nodes(the_node, child)
            if not n:
                the_node.add_child(child)
        return the_node

    def merge_with_node(self, another_node):
        ''' want to return a new instance, not modify current node, so a wrapper
        for a static function, one time new instance, and then modify that in place '''

        # creating a new instance by deseriazling the serialized object
        # since i dont want this to happen recursively, hence the wrapper
        node_to_return = Node.from_dict(self.flatten_to_dict())
        x = Node.merge_nodes(node_to_return, another_node)
        return node_to_return


if __name__ == '__main__':
    ''' preprocessing, so we can work with the Node class'''
    data = eval(open('input.txt').read())
    d1 = data['d1'] # first list of data dicts
    d2 = data['d2'] # second list of data dicts
    # as per you're input example of Dict1 and Dict2
    Dict1 = map(Node.from_dict, d1)
    Dict2 = map(Node.from_dict, d2)

    # assuming Dict2 should just be one element, then Dict2[0]
    Dict2 = Dict2[0]
    result = []
    # try to merge with every dict in Dict1
    for _dict in Dict1:
        res = _dict.merge_with_node(Dict2)
        result.append(res)

    print result


$>python test1.py

“名称”在同一词典中是否始终唯一,或者是否可以复制?@ishez键“名称”的值在同一词典中始终唯一。Dict2中的项是否可能与Dict1的父项不同?是的。。。很好possible@ishez .. 如果两个人都有相同的父母,你会怎么做。例如,如果dict2是[{'name':'A','childs':[{'name':'B','childs':[{'name':'X','childs':None}]}]}],并且如果第一个子项在dict中不相同,那么它应该直接附加在那里,这总是正确的。。。我希望我能恰当地引用我已经写了一个更简洁的版本,有一个树状结构。如果你觉得有用,我可以在这里更新答案。给你-这段代码对我来说工作得很好,我刚刚做了一些修改,使它具有双向性。如果您能在这里发布树形结构代码,我将不胜感激。当我在公司网络中工作时,访问被拒绝。感谢这段代码,这是树遍历方法。。。。大多数情况下,yaml文件是作为配置文件创建的,我更愿意将所有内容作为子节点附加,而不必担心父节点。但这种方法展示了一种新的方法。。谢谢
$> cat input.txt ( From your sample input )
{'d2': [{'childs': [{'childs': [{'childs': None, 'name': 'X'}], 'name': 'C'}], 'name': 'B'}], 'd1': [{'childs': [{'childs': [{'childs': [{'childs': None, 'name': 'D'}], 'name': 'C'}], 'name': 'B'}], 'name': 'A'}, {'childs': None, 'name': 'E'}]}

$>vi test1.py (sorry for the name, your question was too long)
class Node(object):
    def __init__(self, name):
    ''' not making children None, [] is easier to work with '''
        self.name = name
        self.children = []

    def add_child(self, child):
        self.children.append(child)

    def flatten_to_dict(self):
        ''' to get it back to your format '''
        my_dict = {'name': self.name, 'childs': []}

        for child in self.children:
            my_dict['childs'].append(child.flatten_to_dict())

        return my_dict

    @staticmethod
    def from_dict(inp_dict):
        ''' taking the input as dictionaries - your format converter '''
        root = Node(inp_dict['name'])
        if not inp_dict['childs']:
            return root

        for child in inp_dict['childs']:
            root.add_child(Node.from_dict(child))
        return root

    def __repr__(self):
        ''' u know what this is for '''
        return "%s" % self.flatten_to_dict()

    def find_node_with_name(self, name):
        if self.name == name:
            return self

        for child in self.children:
            found_node = child.find_node_with_name(name)
            if found_node:
                return found_node
        return None

    @staticmethod
    def merge_nodes(node1, node2):
        ''' the actual core logic, very simple '''
        the_node = node1.find_node_with_name(node2.name)

        if not the_node:
            return None

        for child in node2.children:
            n = Node.merge_nodes(the_node, child)
            if not n:
                the_node.add_child(child)
        return the_node

    def merge_with_node(self, another_node):
        ''' want to return a new instance, not modify current node, so a wrapper
        for a static function, one time new instance, and then modify that in place '''

        # creating a new instance by deseriazling the serialized object
        # since i dont want this to happen recursively, hence the wrapper
        node_to_return = Node.from_dict(self.flatten_to_dict())
        x = Node.merge_nodes(node_to_return, another_node)
        return node_to_return


if __name__ == '__main__':
    ''' preprocessing, so we can work with the Node class'''
    data = eval(open('input.txt').read())
    d1 = data['d1'] # first list of data dicts
    d2 = data['d2'] # second list of data dicts
    # as per you're input example of Dict1 and Dict2
    Dict1 = map(Node.from_dict, d1)
    Dict2 = map(Node.from_dict, d2)

    # assuming Dict2 should just be one element, then Dict2[0]
    Dict2 = Dict2[0]
    result = []
    # try to merge with every dict in Dict1
    for _dict in Dict1:
        res = _dict.merge_with_node(Dict2)
        result.append(res)

    print result


$>python test1.py