我试图在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}]
它只是附加一个字典作为另一个字典的孩子,但我无法弄清楚,如何在两个字典中迭代然后追加时检查相同的父母。
答案 0 :(得分:1)
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'])
将其添加到list_of_dicts_1。应该这样做。 但是,由于它具有这种层次结构,因此构建树结构对您来说会更有用。
在您的输入中,您调用了两个列表Dict1和Dict2 所以在这里,你调用append_stuff(Dict1,Dict2) 并且Dict1具有所需的输出。
答案 1 :(得分:0)
我提出以下方法:
gen_base
从包含childes和parent的给定字典列表生成数据库。数据库是一个帮助索引不同元素的字典。它包含{..., 'B': {'childs': ['C'], 'parent': 'A'}, ...}
build_tree
创建一个方法,使用生成的数据库构建给定名称的树。merge_from_base
合并数据库元素以形成完整的树。以下是方法:
让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
#
# 1. Generate a data base
#
def gen_base(lst, parent=None, res=None):
"""Generates a data-base with childes and parents"""
if res is None: res = {} # res will contain the required result
if lst is None: return res # Given list (in our case, it is Dict1 + Dict2)
for d in lst: # For each element d in the list ...
if d['name'] in res: # ... if the name exists in the data-base,
if res[d['name']]['childs'] is None: # if it has no child
res[d['name']]['childs'] = []
else: # if there are children
for c in d['childs']: # get teir names in a list
if c['name'] not in res[d['name']]['childs']:
res[d['name']]['childs'].append(c['name'])
else: # ... if the name does not exist in the base
res[d['name']] = { # ... create a new one
'childs':[] if d['childs'] is None else [c['name'] for c in d['childs']],
'parent':parent}
# In any case, do the same for children (recursively)
gen_base(d['childs'], parent=d['name'], res=res)
return res
#
# 2. Build a tree from a root and a data-base
#
def build_tree(base, root):
"""Builds the tree of the given root using informations from the base"""
ret = {} # The result will contain a name and a list of childes
ret['name'] = root # The root is a string such as 'A', 'B', ...
if base[root]['childs'] == []:
ret['childs'] = None
# If there are no children, the tree stops
else:
# # If there are children, the tree continues to grow recursively
ret['childs'] = map(lambda e: build_tree(base, e), base[root]['childs'])
return ret
#
# 3. Merge the data
#
def merge_from_base(base,):
"""Uses the base to get the roots (which 'parent' is None) and complete the trees"""
ret = []
for p in base:
if base[p]['parent'] is None: # The final list contains the roots
# ... and the roots point to their children
ret.append(build_tree(base=base, root=p))
return ret
严重Taha,
答案 2 :(得分:0)
这是一个稍微修改过的Node类,用于构建相同的结构。我觉得核心逻辑在这里更容易理解。
$> 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