Click here to Skip to main content
Click here to Skip to main content

Select Recursive Extension method

By , 2 May 2011
 
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)

About the Author

Partenon
Web Developer
Sweden Sweden
Member
Software developer

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNice onememberShahriar Iqbal Chowdhury2 May '11 - 10:16 
Nice one

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 2 May 2011
Article Copyright 2010 by Partenon
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid