Last active
February 22, 2019 11:43
-
-
Save azureskydiver/273b053d7e43c8de19e0658c35f0eae1 to your computer and use it in GitHub Desktop.
Another hierarchy walker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace AnotherHierarchyWalker | |
{ | |
public class NodeInfo<T> | |
{ | |
public T Node { get; private set; } | |
public NodeInfo<T> Parent { get; private set; } | |
public int Depth { get; private set; } | |
public IEnumerable<T> Path | |
{ | |
get | |
{ | |
var stack = new Stack<T>(); | |
for (var current = Parent; current != null; current = current.Parent) | |
stack.Push(current.Node); | |
return stack; | |
} | |
} | |
public NodeInfo(T node, NodeInfo<T> parent, int depth) | |
{ | |
Node = node; | |
Parent = parent; | |
Depth = depth; | |
} | |
} | |
public interface IHierarchyProvider<T> | |
{ | |
T LoadRootNode(); | |
IEnumerable<T> LoadChildren(T node); | |
} | |
public abstract class HierarchyWalker<T> | |
{ | |
public IHierarchyProvider<T> Provider { get; private set; } | |
public IEnumerable<NodeInfo<T>> Walk(CancellationToken token = new CancellationToken()) | |
=> Walk(Provider.LoadRootNode(), 0, token); | |
public IEnumerable<NodeInfo<T>> Walk(T root, int depth = 0, CancellationToken token = new CancellationToken()) | |
{ | |
Add(new NodeInfo<T>(root, null, depth)); | |
while (Any() && !token.IsCancellationRequested) | |
{ | |
var nodeInfo = Remove(); | |
yield return nodeInfo; | |
var newDepth = nodeInfo.Depth + 1; | |
foreach (var child in Order(Provider.LoadChildren(nodeInfo.Node))) | |
Add(new NodeInfo<T>(child, nodeInfo, newDepth)); | |
} | |
} | |
protected HierarchyWalker(IHierarchyProvider<T> provider) => Provider = provider; | |
protected abstract void Add(NodeInfo<T> nodeInfo); | |
protected abstract NodeInfo<T> Remove(); | |
protected abstract bool Any(); | |
protected abstract IEnumerable<T> Order(IEnumerable<T> children); | |
} | |
public class BreadthFirstHierarchyWalker<T> : HierarchyWalker<T> | |
{ | |
public BreadthFirstHierarchyWalker(IHierarchyProvider<T> provider) : base(provider) { } | |
Queue<NodeInfo<T>> _queue = new Queue<NodeInfo<T>>(); | |
protected override void Add(NodeInfo<T> nodeInfo) => _queue.Enqueue(nodeInfo); | |
protected override NodeInfo<T> Remove() => _queue.Dequeue(); | |
protected override bool Any() => _queue.Any(); | |
protected override IEnumerable<T> Order(IEnumerable<T> children) => children; | |
} | |
public class DepthFirstHierarchyWalker<T> : HierarchyWalker<T> | |
{ | |
public DepthFirstHierarchyWalker(IHierarchyProvider<T> provider) : base(provider) { } | |
Stack<NodeInfo<T>> _stack = new Stack<NodeInfo<T>>(); | |
protected override void Add(NodeInfo<T> nodeInfo) => _stack.Push(nodeInfo); | |
protected override NodeInfo<T> Remove() => _stack.Pop(); | |
protected override bool Any() => _stack.Any(); | |
protected override IEnumerable<T> Order(IEnumerable<T> children) => children.Reverse(); | |
} | |
class IntHierarchyProvider : IHierarchyProvider<int> | |
{ | |
public int MaxDepth { get; private set; } | |
public IntHierarchyProvider(int maxDepth) => MaxDepth = maxDepth; | |
public IEnumerable<int> LoadChildren(int node) => node < MaxDepth ? new List<int>() { node + 1 } : new List<int>(); | |
public int LoadRootNode() => 1; | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var walker = new DepthFirstHierarchyWalker<int>(new IntHierarchyProvider(100000)); | |
foreach (var nodeInfo in walker.Walk()) | |
{ | |
if (nodeInfo.Node % 1000 == 0) | |
Console.WriteLine(nodeInfo.Node); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment