Skip to content

Instantly share code, notes, and snippets.

@alonstar
Last active July 26, 2018 03:38
Show Gist options
  • Save alonstar/74a40641913effd6b7eed55614b77c41 to your computer and use it in GitHub Desktop.
Save alonstar/74a40641913effd6b7eed55614b77c41 to your computer and use it in GitHub Desktop.
Make trees
/// <summary>
/// Defines the <see cref="Extensions" />
/// </summary>
public static class TreeExtensions
{
/// <summary>
/// The FindChildren
/// </summary>
/// <typeparam name="T">T</typeparam>
/// <param name="source">The source<see cref="IEnumerable{Node{T}}"/></param>
/// <param name="predicate">The predicate<see cref="Func{Node{T}, bool}"/></param>
/// <returns>The <see cref="IEnumerable{Node{T}}"/></returns>
public static IEnumerable<Node<T>> FindChildren<T>(this IEnumerable<Node<T>> source, Func<Node<T>, bool> predicate)
{
return source.FindNode(predicate).Children.Flatten(p => p.Children);
}
/// <summary>
/// The FindNode
/// </summary>
/// <typeparam name="T">T</typeparam>
/// <param name="source">The source<see cref="IEnumerable{Node{T}}"/></param>
/// <param name="predicate">The predicate<see cref="Func{Node{T}, bool}"/></param>
/// <returns>The <see cref="Node{T}"/></returns>
public static Node<T> FindNode<T>(this IEnumerable<Node<T>> source, Func<Node<T>, bool> predicate)
{
return source.Flatten(p => p.Children).FirstOrDefault(predicate);
}
/// <summary>
/// The FindParents
/// </summary>
/// <typeparam name="T">T</typeparam>
/// <param name="source">The source<see cref="Node{T}"/></param>
/// <returns>The <see cref="IEnumerable{Node{T}}"/></returns>
public static IEnumerable<Node<T>> FindParents<T>(this Node<T> source)
{
var root = source;
var list = new List<Node<T>>();
while (root.Parent != null)
{
list.Add(root.Parent);
root = root.Parent;
}
return list;
}
/// <summary>
/// The Flatten
/// </summary>
/// <typeparam name="T">T</typeparam>
/// <param name="source">The source<see cref="IEnumerable{T}"/></param>
/// <param name="f">The f<see cref="Func{T, IEnumerable{T}}"/></param>
/// <returns>The <see cref="IEnumerable{T}"/></returns>
public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> f)
{
return source.SelectMany(c => f(c).Flatten(f)).Concat(source);
}
/// <summary>
/// The Hierarchize
/// </summary>
/// <typeparam name="T">T</typeparam>
/// <typeparam name="TKey">TKey</typeparam>
/// <typeparam name="TOrderKey">TOrderKey</typeparam>
/// <param name="elements">The elements<see cref="IEnumerable{T}"/></param>
/// <param name="rootId">The rootId<see cref="TKey"/></param>
/// <param name="keySelector">The keySelector<see cref="Func{T, TKey}"/></param>
/// <param name="parentKeySelector">The parentKeySelector<see cref="Func{T, TKey}"/></param>
/// <param name="orderKeySelector">The orderKeySelector<see cref="Func{T, TOrderKey}"/></param>
/// <returns>The <see cref="IEnumerable{Node{T}}"/></returns>
public static IEnumerable<Node<T>> Hierarchize<T, TKey, TOrderKey>(
this IEnumerable<T> elements,
TKey rootId,
Func<T, TKey> keySelector,
Func<T, TKey> parentKeySelector,
Func<T, TOrderKey> orderKeySelector)
{
var families = elements.ToLookup(parentKeySelector);
var childrenFetcher = default(Func<TKey, Node<T>, IList<Node<T>>>);
childrenFetcher = (parentId, parent) =>
{
var children = families[parentId]
.OrderBy(orderKeySelector)
.Select(x => new Node<T>(x))
.ToList();
children.ForEach(c =>
{
c.Children = childrenFetcher(keySelector(c.Value), c);
c.Parent = parent;
});
return children;
};
return childrenFetcher(rootId, null);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment