Considérons que nous avons un tas de sous-contraintes qui ressemblent à ceci :
subtree1 = {
"id": "root",
"children": [
{
"id": "file",
"caption": "File",
"children": []
},
{
"id": "edit",
"caption": "Edit",
"children": []
},
{
"id": "tools",
"caption": "Tools",
"children": [
{
"id": "packages",
"caption": "Packages",
"children": []
}
]
},
{
"id": "help",
"caption": "Help",
"children": []
},
]
}
subtree2 = {
"id": "root",
"children": [
{
"id": "file",
"caption": "File",
"children": [
{"caption": "New"},
{"caption": "Exit"},
]
}
]
}
subtree3 = {
"id": "root",
"children": [
{
"id": "edit",
"children": [
{"caption": "Copy"},
{"caption": "Cut"},
{"caption": "Paste"},
]
},
{
"id": "help",
"children": [
{"caption": "About"},
]
}
]
}
subtree4 = {
"id": "root",
"children": [
{
"id": "edit",
"children": [
{
"id": "text",
"caption": "Text",
"children": [
{ "caption": "Insert line before" },
{ "caption": "Insert line after" }
]
}
]
}
]
}
J'essaie de comprendre comment coder un merge
en procédant par exemple de la manière suivante :
tree0 = merge(subtree1, subtree2)
tree0 = merge(tree0, subtree3)
tree0 = merge(tree0, subtree4)
produira :
tree0 = {
"id": "root",
"children": [
{
"id": "file",
"caption": "File",
"children": [
{"caption": "New"},
{"caption": "Exit"},
]
},
{
"id": "edit",
"caption": "Edit",
"children": [
{"caption": "Copy"},
{"caption": "Cut"},
{"caption": "Paste"},
{
"id": "text",
"caption": "Text",
"children": [
{ "caption": "Insert line before" },
{ "caption": "Insert line after" }
]
}
]
},
{
"id": "tools",
"caption": "Tools",
"children": [
{
"id": "packages",
"caption": "Packages",
"children": []
}
]
},
{
"id": "help",
"caption": "Help",
"children": [
{"caption": "About"},
]
},
]
}
mais en faisant quelque chose comme ça :
tree1 = merge(subtree1, subtree2)
tree1 = merge(tree1, subtree4)
tree1 = merge(tree1, subtree3)
produirait :
tree1 = {
"id": "root",
"children": [
{
"id": "file",
"caption": "File",
"children": [
{"caption": "New"},
{"caption": "Exit"},
]
},
{
"id": "edit",
"caption": "Edit",
"children": [
{
"id": "text",
"caption": "Text",
"children": [
{ "caption": "Insert line before" },
{ "caption": "Insert line after" }
]
},
{"caption": "Copy"},
{"caption": "Cut"},
{"caption": "Paste"},
]
},
{
"id": "tools",
"caption": "Tools",
"children": [
{
"id": "packages",
"caption": "Packages",
"children": []
}
]
},
{
"id": "help",
"caption": "Help",
"children": [
{"caption": "About"},
]
},
]
}
Autrement dit, le chargement des sous-arbres dans le même ordre produira toujours le même arbre, mais si vous utilisez la même liste de sous-arbres dans un ordre différent, vous n'êtes pas assuré de produire le même arbre (car les listes d'enfants peuvent être étendues dans un ordre différent).
J'ai déjà essayé de coder cela, mais je ne sais pas comment faire. merge
et c'est là ma question. Quelqu'un pourrait-il fournir le code/pseudocode/explication pour que je puisse le mettre en œuvre ?
PS : Vous trouverez ci-dessous quelques tentatives aléatoires que je pensais pouvoir mener à la victoire.
if __name__ == '__main__':
from collections import defaultdict
subtree1 = {
"id": "root",
"children": [
{
"id": "file",
"caption": "File",
"children": []
},
{
"id": "edit",
"caption": "Edit",
"children": []
},
{
"id": "tools",
"caption": "Tools",
"children": [
{
"id": "packages",
"caption": "Packages",
"children": []
}
]
},
{
"id": "help",
"caption": "Help",
"children": []
},
]
}
subtree2 = {
"id": "root",
"children": [
{
"id": "file",
"caption": "File",
"children": [
{"caption": "New"},
{"caption": "Exit"},
]
}
]
}
subtree3 = {
"id": "root",
"children": [
{
"id": "edit",
"children": [
{"caption": "Copy"},
{"caption": "Cut"},
{"caption": "Paste"},
]
},
{
"id": "help",
"children": [
{"caption": "About"},
]
}
]
}
subtree4 = {
"id": "root",
"children": [
{
"id": "edit",
"children": [
{
"id": "text",
"caption": "Text",
"children": [
{"caption": "Insert line before"},
{"caption": "Insert line after"}
]
}
]
}
]
}
lst = [
subtree1,
subtree2,
subtree3,
subtree4
]
def traverse(node, path=[]):
yield node, tuple(path)
for c in node.get("children", []):
path.append(c.get("id", None))
yield from traverse(c)
path.pop()
# Levels & Hooks
dct_levels = defaultdict(list)
dct_hooks = defaultdict(list)
for subtree in lst:
for n, p in traverse(subtree):
if p not in dct_levels[len(p)]:
dct_levels[len(p)].append(p)
dct_hooks[p].append(n)
print(dct_levels)
print(dct_hooks[("file",)])
# Merge should happen here
tree = {
"id": "root",
"children": []
}
for level in range(1, max(dct_levels.keys()) + 1):
print("populating level", level, dct_levels[level])
mais je ne suis pas sûr de créer les bonnes structures / aides car le fonctionnement de l'algorithme n'est pas encore clair... c'est l'objet de cette question.