|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
namespace ZeroLevel.Services.Trees
|
|
|
|
|
{
|
|
|
|
|
public static class TreesVisitor
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extract tree branches to plain array
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T">Node type</typeparam>
|
|
|
|
|
/// <param name="root">Tree root</param>
|
|
|
|
|
/// <param name="childrenExtractor">Extractor of node children</param>
|
|
|
|
|
/// <returns>Array of tree branches</returns>
|
|
|
|
|
public static List<T[]> ExtractBranches<T>(T root, Func<T, IEnumerable<T>> childrenExtractor)
|
|
|
|
|
{
|
|
|
|
|
if (root == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(root));
|
|
|
|
|
if (childrenExtractor == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(childrenExtractor));
|
|
|
|
|
var result = new List<T[]>();
|
|
|
|
|
TraversTreeBrunches(root, childrenExtractor, brunch =>
|
|
|
|
|
{
|
|
|
|
|
result.Add(brunch.ToArray());
|
|
|
|
|
});
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Selects all branches of the tree, returning an array of branches consisting of the specified node values.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T">Type of tree nodes</typeparam>
|
|
|
|
|
/// <typeparam name="TCode">Value type for returned branch elements</typeparam>
|
|
|
|
|
/// <param name="root">Root</param>
|
|
|
|
|
/// <param name="childrenExtractor">Selects child nodes for the current node.</param>
|
|
|
|
|
/// <param name="codeExtractor">Select the value of the node</param>
|
|
|
|
|
/// <returns>List of tree branches</returns>
|
|
|
|
|
public static List<TCode[]> SpecifyExtractBranches<T, TCode>(T root,
|
|
|
|
|
Func<T, IEnumerable<T>> childrenExtractor,
|
|
|
|
|
Func<T, TCode> codeExtractor)
|
|
|
|
|
{
|
|
|
|
|
if (root == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(root));
|
|
|
|
|
if (childrenExtractor == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(childrenExtractor));
|
|
|
|
|
if (codeExtractor == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(codeExtractor));
|
|
|
|
|
var result = new List<TCode[]>();
|
|
|
|
|
TraversTreeBrunches(root, childrenExtractor, brunch =>
|
|
|
|
|
{
|
|
|
|
|
result.Add(brunch.Select(i => codeExtractor(i)).ToArray());
|
|
|
|
|
});
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Performs tree branch traversal.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void TraversTreeBrunches<T>(T root,
|
|
|
|
|
Func<T, IEnumerable<T>> childrenExtractor,
|
|
|
|
|
Action<IEnumerable<T>> handler)
|
|
|
|
|
{
|
|
|
|
|
if (root == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(root));
|
|
|
|
|
if (childrenExtractor == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(childrenExtractor));
|
|
|
|
|
if (handler == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(handler));
|
|
|
|
|
var brunch = new List<T>();
|
|
|
|
|
brunch.Add(root);
|
|
|
|
|
foreach (var child in childrenExtractor(root))
|
|
|
|
|
{
|
|
|
|
|
TraversNode<T>(child, brunch, childrenExtractor, handler);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void TraversNode<T>(T node, List<T> brunch, Func<T, IEnumerable<T>> childrenExtractor, Action<IEnumerable<T>> handler)
|
|
|
|
|
{
|
|
|
|
|
if (node == null)
|
|
|
|
|
{
|
|
|
|
|
handler(brunch);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var currentBrunch = new List<T>(brunch);
|
|
|
|
|
currentBrunch.Add(node);
|
|
|
|
|
var children = childrenExtractor(node);
|
|
|
|
|
if (children != null && children.Any())
|
|
|
|
|
{
|
|
|
|
|
foreach (var child in childrenExtractor(node))
|
|
|
|
|
{
|
|
|
|
|
TraversNode<T>(child, currentBrunch, childrenExtractor, handler);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
handler(currentBrunch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|