I am trying to develop a reactive DFS implementation that produces distinct nodes, without traversing unnecessary paths. The tree may contain duplicate/equal nodes. If a node has been traversed, then all of it's children have been traversed as well, hence we can stop expanding the traversal if we re-encounter a node.
class Traversal {
//exposed method with understandable signature
public IObservable<Node> DepthFirst(Node root) {
return DepthFirstRecursive(root, new List<Node>(), new SomeStatefulHelper());
}
//hidden method with accumulator for cutting
private IObservable<Node> DepthFirstRecursive(Node root, List<Node> accuFilter, SomeHelper helper) {
return root.GetChildren().AsObservable()
//here we cut traversal:
.Where(n => !accuFilter.Contains(n))
//cannot do SelectMany, because we want sequential processing:
.Select(n => DepthFirstRecursive(n, accuFilter, helper)).Concat()
.Concat(Observable.Return(root))
//adding results to accumulator
.Do(accuFilter.Add)
}
}
class Node : IEquatable<Node> {
public IEnumerable<Node> GetChildren(SomeHelper helper) {
//produce child nodes
}
...
}
The accumulator is not pretty. It's basically a side effect woven through the otherwise elegant reactive implementation. How can I get rid of it using Rx? Observable.Distinct()
is not going to cut it (pun intended), since that can only operate at the very end of the chain (where the .Do
is).
Also, with the helper I'm getting an "Implicitly captured closure: helper" warning on the =>
in the .Where
. I don't see that this warning is relevant. Is it? How do I get rid of it?