Ho scritto del codice che trova tutti i percorsi a monte di una determinata portata in una rete di flusso dendritico. Come esempio, se rappresento la seguente rete:Efficienza di ricerca del percorso in Python
4 -- 5 -- 8
/
2 --- 6 - 9 -- 10
/ \
1 -- 11
\
3 ----7
come un insieme di coppie padre-figlio:
{(11, 9), (10, 9), (9, 6), (6, 2), (8, 5), (5, 4), (4, 2), (2, 1), (3, 1), (7, 3)}
esso ritornerà tutti i percorsi a monte di un nodo, ad esempio:
get_paths(h, 1) # edited, had 11 instead of 1 in before
[[Reach(2), Reach(6), Reach(9), Reach(11)], [Reach(2), Reach(6), Reach(9), Reach(10)], [Reach(2), Reach(4), Reach(5), Reach(8)], [Reach(3), Reach(7)]]
Il codice è incluso di seguito.
La mia domanda è: lo dico in riferimento questo per ogni raggiungere in un grande (ad esempio, New England) per cui un dato portata può avere milioni di percorsi. Probabilmente non c'è modo di evitare che si tratti di un'operazione molto lunga, ma esiste un modo pitonioso per eseguire questa operazione in modo tale che non vengano generati percorsi nuovi ogni volta?
Ad esempio, se corro get_paths (h, 2) get_paths e tutti i percorsi a monte da 2 si trovano, posso successivamente eseguire (h, 1) senza ripercorrere tutti i percorsi a 2?
import collections
# Object representing a stream reach. Used to construct a hierarchy for accumulation function
class Reach(object):
def __init__(self):
self.name = None
self.ds = None
self.us = set()
def __repr__(self):
return "Reach({})".format(self.name)
def build_hierarchy(flows):
hierarchy = collections.defaultdict(lambda: Reach())
for reach_id, parent in flows:
if reach_id:
hierarchy[reach_id].name = reach_id
hierarchy[parent].name = parent
hierarchy[reach_id].ds = hierarchy[parent]
hierarchy[parent].us.add(hierarchy[reach_id])
return hierarchy
def get_paths(h, start_node):
def go_up(n):
if not h[n].us:
paths.append(current_path[:])
for us in h[n].us:
current_path.append(us)
go_up(us.name)
if current_path:
current_path.pop()
paths = []
current_path = []
go_up(start_node)
return paths
test_tree = {(11, 9), (10, 9), (9, 6), (6, 2), (8, 5), (5, 4), (4, 2), (2, 1), (3, 1), (7, 3)}
h = build_hierarchy(test_tree)
p = get_paths(h, 1)
EDIT: Qualche settimana fa ho fatto una domanda simile su come trovare raggiunge "ALL" a monte in una rete e ha ricevuto una risposta eccellente che è stato molto veloce:
class Node(object):
def __init__(self):
self.name = None
self.parent = None
self.children = set()
self._upstream = set()
def __repr__(self):
return "Node({})".format(self.name)
@property
def upstream(self):
if self._upstream:
return self._upstream
else:
for child in self.children:
self._upstream.add(child)
self._upstream |= child.upstream
return self._upstream
import collections
edges = {(11, 9), (10, 9), (9, 6), (6, 2), (8, 5), (5, 4), (4, 2), (2, 1), (3, 1), (7, 3)}
nodes = collections.defaultdict(lambda: Node())
for node, parent in edges:
nodes[node].name = node
nodes[parent].name = parent
nodes[node].parent = nodes[parent]
nodes[parent].children.add(nodes[node])
ho notato che la def upstream(): parte di questo codice aggiunge nodi upstream in ordine sequenziale, ma poiché è una funzione iterativa non riesco a trovare un buon modo per aggiungerli a una singola lista. Forse c'è un modo per modificare questo codice che conserva l'ordine.
IMHO se sto capendo correttamente penso che la domanda non è un problema 'python-way' piuttosto un problema di database o struttura, Ad esempio è possibile aggiungere alcuni dati alla coppia tuple genitore-figlio che indicherà il numero di figli e 0 rappresenterà una copertura non testata, tra l'altro se sono così tanti raggiungere dove hai intenzione di memorizzare i dati? puoi facilmente ottenere problemi di memoria ... –