Skip to content

Instantly share code, notes, and snippets.

@azureskydiver
Last active February 22, 2019 11:43
Show Gist options
  • Save azureskydiver/273b053d7e43c8de19e0658c35f0eae1 to your computer and use it in GitHub Desktop.
Save azureskydiver/273b053d7e43c8de19e0658c35f0eae1 to your computer and use it in GitHub Desktop.
Another hierarchy walker
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