Click here to Skip to main content
15,880,364 members
Articles / Recursion
Tip/Trick

Select Recursive Extension method

Rate me:
Please Sign up or sign in to vote.
4.80/5 (4 votes)
2 May 2011CPOL 22.4K   1   1
An extension method to the IEnumerable`1 interface that can select all children recursively of an entity in a tree like structure
This is an extension method to the IEnumerable`1 interface that can select all children recursively of an entity in a tree like structure.

Example


var allChildren = node.ChildNodes.SelectRecursive(n => n.ChildNodes);


/// <summary>
/// A set of <see cref="T:System.Collections.Generic.IEnumerable`1" /> extensions methods
/// </summary>
public static class IEnumerableExtensions
{
    /// <summary>
    /// Projects each element of a sequence recursively to an <see cref="T:System.Collections.Generic.IEnumerable`1" />
    /// and flattens the resulting sequences into one sequence.
    /// </summary>
    /// <typeparam name="T">The type of the elements.</typeparam>
    /// <param name="source">A sequence of values to project.</param>
    /// <param name="selector">A transform function to apply to each element.</param>
    /// <returns>
    /// An <see cref="T:System.Collections.Generic.IEnumerable`1" /> whose elements
    /// who are the result of invoking the recursive transform function on each element of the input sequence.
    /// </returns>
    /// <example>
    /// node.ChildNodes.SelectRecursive(n => n.ChildNodes);
    /// </example>
    public static IEnumerable<IRecursion<T>> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
    {
        return SelectRecursive(source, selector, null);
    }
    /// <summary>
    /// Projects each element of a sequence recursively to an <see cref="T:System.Collections.Generic.IEnumerable`1" />
    /// and flattens the resulting sequences into one sequence.
    /// </summary>
    /// <typeparam name="T">The type of the elements.</typeparam>
    /// <param name="source">A sequence of values to project.</param>
    /// <param name="selector">A transform function to apply to each element.</param>
    /// <param name="predicate">A function to test each element for a condition in each recursion.</param>
    /// <returns>
    /// An <see cref="T:System.Collections.Generic.IEnumerable`1" /> whose elements are the result of
    /// invoking the recursive transform function on each element of the input sequence.
    /// </returns>
    /// <example>
    /// node.ChildNodes.SelectRecursive(n => n.ChildNodes, m => m.Depth < 2);
    /// </example>
    public static IEnumerable<IRecursion<T>> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector, Func<IRecursion<T>, bool> predicate)
    {
        return SelectRecursive(source, selector, predicate, 0);
    }
    private static IEnumerable<IRecursion<T>> SelectRecursive<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> selector, Func<IRecursion<T>, bool> predicate, int depth)
    {
        var q = source
            .Select(item => new Recursion<T>(depth, item))
            .Cast<IRecursion<T>>();
        if (predicate != null)
            q = q.Where(predicate);
        foreach (var item in q)
        {
            yield return item;
            foreach (var item2 in SelectRecursive(selector(item.Item), selector, predicate, depth + 1))
                yield return item2;
        }
    }
    private class Recursion<T> : IRecursion<T>
    {
        private int _depth;
        private T _item;
        public int Depth
        {
            get { return _depth; }
        }
        public T Item
        {
            get { return _item; }
        }
        public Recursion(int depth, T item)
        {
            _depth = depth;
            _item = item;
        }
    }
}

/// <summary>
/// Represents an item in a recursive projection.
/// </summary>
/// <typeparam name="T">The type of the item</typeparam>
public interface IRecursion<T>
{
    /// <summary>
    /// Gets the recursive depth.
    /// </summary>
    /// <value>The depth.</value>
    int Depth { get; }
    /// <summary>
    /// Gets the item.
    /// </summary>
    /// <value>The item.</value>
    T Item { get; }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Sweden Sweden
Software developer

Comments and Discussions

 
GeneralNice one Pin
Shahriar Iqbal Chowdhury/Galib2-May-11 10:16
professionalShahriar Iqbal Chowdhury/Galib2-May-11 10:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.