问题
I am trying to create a list with all possible paths in a tree. I have following structure given (subset from DB):
text = """
1,Product1,INVOICE_FEE,
3,Product3,INVOICE_FEE,
7,Product7,DEFAULT,
2,Product2,DEFAULT,7
4,Product4,DEFAULT,7
5,Product5,DEFAULT,2
"""
where the columns are: ID, product-name, invoice-type, reference-to-parent-ID. I would like to create list with all possible paths, like in the example:
[[Product1],[Product3],[Product7,Product2,Product5],[Product7,Product4]]
I do following:
lines = [ l.strip() for l in text.strip().splitlines() ]
hierarchy = [ tuple(l.split(',')) for l in lines ]
parents = defaultdict(list)
for p in hierarchy:
parents[p[3]].append(p)
for creation the tree and then I would like to find all paths:
def pathsMet(parents, node=''):
childNodes = parents.get(node)
if not childNodes:
return []
paths = []
for ID, productName, invoiceType, parentID in childNodes:
paths.append([productName] + pathsMet(parents, ID))
return paths
print(pathsMet(parents))
The result which I got is following:
[['FeeCashFlow1'], ['FeeCashFlow3'], ['PrincipalCashFlow7', ['AmortisationCashFlow3', ['AmortisationCashFlow2']], ['AmortisationCashFlow4']]]
How to correct the code to have following output:
[['FeeCashFlow1'], ['FeeCashFlow3'], ['PrincipalCashFlow7', 'AmortisationCashFlow3', 'AmortisationCashFlow2'], ['PrincipalCashFlow7','AmortisationCashFlow4']]
回答1:
You can do this by first building a tree of your data nodes and then going through all branches to build a list of paths:
text = """
1,Product1,INVOICE_FEE,
3,Product3,INVOICE_FEE,
7,Product7,DEFAULT,
2,Product2,DEFAULT,7
4,Product4,DEFAULT,7
5,Product5,DEFAULT,2
"""
data = [ line.split(",") for line in text.split("\n") if line.strip() ]
keys = { k:name for k,name,*_ in data } # to get names from keys
tree = { k:{} for k in keys } # initial tree structure with all keys
root = tree[""] = dict() # tree root
for k,_,_,parent in data:
tree[parent].update({k:tree[k]}) # connect children to their parent
nodes = [[k] for k in root] # cumulative paths of keys
paths = [] # list of paths by name
while nodes:
kPath = nodes.pop(0)
subs = tree[kPath[-1]] # get children
if subs: nodes.extend(kPath+[k] for k in subs) # accumulate nodes
else : paths.append([keys[k] for k in kPath]) # return path if leaf node
output:
print(paths)
[['Product1'], ['Product3'], ['Product7', 'Product4'], ['Product7', 'Product2', 'Product5']]
回答2:
Your code seems correct except that you are appending entire list to the paths
variable, instead of list elements.
Try this modification:
def pathsMet(parents, node=''):
childNodes = parents.get(node)
if not childNodes:
return [[]]
paths = []
for ID, productName, invoiceType, parentID in childNodes:
for p in pathsMet(parents, ID):
paths.append([productName] + p)
return paths
来源:https://stackoverflow.com/questions/61597415/find-all-possible-paths-in-a-tree-in-python