/// <summary>
        /// Gets a node's leaves, i.e. all descendants of that node that do not have children.  If
        /// the node has no children then the node itself is returned.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">
        /// The node whose leaves are to be returned.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the node's
        /// leaves.
        /// </returns>
        public static IEnumerable <T> GetLeaves <T>(this ITreeWalker <T> walker, T node)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to hold enumerators and push the child enumerator of 'node'.
            Stack <IEnumerator <T> > stack = new Stack <IEnumerator <T> >();

            stack.Push(walker.GetChildren(node).GetEnumerator());

            if (!stack.Peek().MoveNext())
            {
                // If the enumerator on the stack has no items then 'node' is a leaf node.
                // Dispose of the enumerator and yield 'node' and we are done.
                stack.Pop().Dispose();
                yield return(node);
            }
            else
            {
                // The current node is now the first child of the 'node' parameter.
                // Continue looping as long as the stack has enumerators on it.
                while (stack.Count > 0)
                {
                    // Push the current node's enumerator on the stack.
                    stack.Push(walker.GetChildren(stack.Peek().Current).GetEnumerator());

                    // Continue pushing enumerators on the stack as long the enumerator on the top
                    // of the stack has items.
                    while (stack.Peek().MoveNext())
                    {
                        stack.Push(walker.GetChildren(stack.Peek().Current).GetEnumerator());
                    }

                    // Once we reach an enumerator that has no items pop that enumerator and
                    // dispose of it.
                    stack.Pop().Dispose();

                    // The 'Current' property of the enumerator on the top of the stack is a leaf
                    // node.  Return it.
                    yield return(stack.Peek().Current);

                    // Continue popping enumerators off of the stack and disposing of them until
                    // we reach an enumerator with another item.  That item become the current
                    // node.
                    while (stack.Count > 0 && !stack.Peek().MoveNext())
                    {
                        stack.Pop().Dispose();
                    }
                }
            }
        }
        /// <summary>
        /// Gets a node and the node's siblings, i.e. all nodes that share the same parent.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">
        /// The node whose siblings are to be returned.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains the
        /// siblings.
        /// </returns>
        public static IEnumerable <T> GetSiblingsAndSelf <T>(this ITreeWalker <T> walker, T node)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Get the node's parent.
            T parent;

            if (walker.TryGetParent(node, out parent))
            {
                // Return all of the parent's children with the exception of the original node.
                return
                    (walker
                     .GetChildren(parent));
            }
            else
            {
                // If the node does not have a parent then return the node.
                return(new T[] { node });
            }
        }
        /// <summary>
        /// Gets a node's siblings, i.e. all nodes that share the same parent.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">
        /// The node whose siblings are to be returned.
        /// </param>
        /// <param name="comparer">
        /// An <see cref="System.Collections.Generic.IEqualityComparer&lt;T&gt;"/> that knows how
        /// to compare two nodes for equality.  This is used to make sure that
        /// <paramref name="node"/> is not returned in the resulting
        /// <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/>.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains the
        /// siblings.
        /// </returns>
        public static IEnumerable <T> GetSiblings <T>(this ITreeWalker <T> walker, T node, IEqualityComparer <T> comparer)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // If the comparer is null then use the default comparer.
            comparer = comparer ?? EqualityComparer <T> .Default;

            // Get the node's parent.
            T parent;

            if (walker.TryGetParent(node, out parent))
            {
                // Return all of the parent's children with the exception of the original node.
                return
                    (walker
                     .GetChildren(parent)
                     .Where(x => !comparer.Equals(node, x)));
            }
            else
            {
                // If the node does not have a parent then return an empty IEnumerable.
                return(Enumerable.Empty <T>());
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Gets children based on a predicate.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">
        /// The root node to be queried.
        /// </param>
        /// <param name="predicate">
        /// A predicate to test each child for selection.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// matching children.
        /// </returns>
        public static IEnumerable <T> GetChildren <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, bool> predicate)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            if (predicate == null)
            {
                throw new ArgumentNullException("predicate");
            }

            return
                (walker
                 .GetChildren(node)
                 .Where(predicate));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Gets the children that match the <paramref name="key"/>.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="nodes">
        /// The root nodes to be queried.
        /// </param>
        /// <param name="key">
        /// The key that each child will be compared to.
        /// </param>
        /// <param name="comparer">
        /// The <see cref="IEqualityComparer&lt;T&gt;"/> used to compare the key and the child.  If
        /// this is null then the default <see cref="EqualityComparer&lt;T&gt;.Default"/> will be
        /// used.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// matching children.
        /// </returns>
        public static IEnumerable <T> GetChildren <T>(
            this ITreeWalker <T> walker,
            IEnumerable <T> nodes,
            T key,
            IEqualityComparer <T> comparer)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            // If the comparer is null then use the defautl comparer for that type.
            comparer = comparer ?? EqualityComparer <T> .Default;

            return
                (nodes
                 .SelectMany(n => walker.GetChildren(n))
                 .Where(n => comparer.Equals(key, n)));
        }
        /// <summary>
        /// Gets the child at the specified index or the default value of the specified type.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">The node whose child is to be returned.</param>
        /// <param name="index">The index of the child to retrieve.</param>
        /// <returns>The child node at the specified index or the default value.</returns>
        /// /// <exception cref="ArgumentNullException">
        /// If <paramref name="walker"/> or <paramref name="node"/> is null.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// If <paramref name="index"/> is less than zero.
        /// </exception>
        public static T GetChildAtOrDefault <T>(
            this ITreeWalker <T> walker,
            T node,
            int index)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            return
                (walker
                 .GetChildren(node)
                 .ElementAtOrDefault(index));
        }
        /// <summary>
        /// Gets the child at the specified index or the default value if the index is out of
        /// range.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="nodes">The nodes whose children are to be returned.</param>
        /// <param name="index">The index of the child to retrieve.</param>
        /// <returns>
        /// The child node at the specified index or default values for each of the nodes in
        /// <see cref="nodes"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="walker"/> or <paramref name="nodes"/> is null.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// If <paramref name="index"/> is less than zero.
        /// </exception>
        public static IEnumerable <T> GetChildAtOrDefault <T>(
            this ITreeWalker <T> walker,
            IEnumerable <T> nodes,
            int index)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }

            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            return
                (nodes
                 .Select(n =>
                         walker
                         .GetChildren(n)
                         .ElementAtOrDefault(index)));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Enumerates a tree using the pre-order traversal method.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">The root node of the tree that is to be traversed.</param>
        /// <param name="excludeSubtreePredicate">
        /// A <see cref="System.Func&lt;T, Int32, Boolean&gt;"/> that determines if the current node
        /// that is being evaluated (and all of its descendants) should be included in the
        /// traversal.  This allows for short-circuiting of the pre-order traversal by excluding
        /// particular subtrees from the traversal.  The first argument is the current node being
        /// evaluated and the second argument is the depth of the current node relative to the
        /// original node that the traversal began on.
        /// </param>
        /// <param name="excludeOption">
        /// Used in conjunction with the <paramref name="excludeSubtreePredicate"/>.  Determines
        /// if the entire subtree should be excluded or just its children.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// nodes in the tree ordered based on a pre-order traversal.
        /// </returns>
        public static IEnumerable <T> PreOrderTraversal <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, int, bool> excludeSubtreePredicate,
            ExcludeOption excludeOption)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to keep track of the branches being traversed.
            Stack <IEnumerator <T> > enumerators = new Stack <IEnumerator <T> >();

            enumerators.Push(Enumerable.Repeat(node, 1).GetEnumerator());

            // Loop as long as we have an enumerator on the stack.  When we have popped the last
            // one off the stack the traversal is complete.
            while (enumerators.Count > 0)
            {
                if (enumerators.Peek().MoveNext())
                {
                    node = enumerators.Peek().Current;

                    // If the 'excludeSubtreePredicate' is not null and evaluates to true then
                    // yield the current node if 'excludeOption' is set to exclude the children.
                    // Otherwise, do not yield anything.
                    if (excludeSubtreePredicate != null &&
                        excludeSubtreePredicate.Invoke(node, enumerators.Count - 1))
                    {
                        if (excludeOption == ExcludeOption.ExcludeDescendants)
                        {
                            yield return(node);
                        }
                    }
                    else
                    {
                        // Yield the current node then push it and its children onto the
                        // stack.
                        yield return(node);

                        enumerators.Push(walker.GetChildren(node).GetEnumerator());
                    }
                }
                else
                {
                    // Pop the enumerator and dispose of it.
                    enumerators.Pop().Dispose();
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Gets the height of the node.  The height is measured by the number of edges between
        /// <paramref name="node"/> and the deepest leaf.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">
        /// The node whose height is to be returned.
        /// </param>
        /// <returns>
        /// The number of edges between <paramref name="node"/> and the deepest leaf.
        /// </returns>
        public static int GetHeight <T>(this ITreeWalker <T> walker, T node)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to hold enumerators and push the child enumerator of 'node'.
            Stack <IEnumerator <T> > stack = new Stack <IEnumerator <T> >();

            stack.Push(walker.GetChildren(node).GetEnumerator());

            // Keep track of the max height.
            int height = 0;

            // Continue looping as long as the stack has enumerators on it.
            // If an enumerator has an item push that item's child enumerator on the stack and
            // update 'height'.  Otherwise, pop the enumerator off the stack and dispose of it.
            while (stack.Count > 0)
            {
                if (stack.Peek().MoveNext())
                {
                    stack.Push(walker.GetChildren(stack.Peek().Current).GetEnumerator());
                    // If the stack height (minus one because height is zero based) is greater
                    // than the current height then update the current height.
                    if (stack.Count - 1 > height)
                    {
                        height = stack.Count - 1;
                    }
                }
                else
                {
                    stack.Pop().Dispose();
                }
            }

            return(height);
        }
        /// <summary>
        /// Tries to get the child at the specified index.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="nodes">The nodes whose children are to be returned.</param>
        /// <param name="index">The index of the child to retrieve.</param>
        /// <param name="child">
        /// The child that was found at the specified index or a default value if the index was
        /// out of range.
        /// </param>
        /// <returns>
        /// True, if a child was found at the specified index; false, otherwise.
        /// </returns>
        internal static bool TryGetChildAt <T>(
            this ITreeWalker <T> walker,
            T node,
            int index,
            out T child)
        {
            // Performance optimization.  Checking to see if the result from GetChildren returns
            // an IList.  If it does then we can simply get the child using the list's indexer
            // property.
            IList <T> list = walker.GetChildren(node) as IList <T>;

            if (list != null)
            {
                // If the index is within bounds then get the child an return true.
                if (index < list.Count)
                {
                    child = list[index];
                    return(true);
                }
            }
            else
            {
                // Iterate over each child, decrementing the index while doing so.
                // If the index reaches 0 then we have found the child.
                // Get the child and return true.
                using (IEnumerator <T> enumerator = walker.GetChildren(node).GetEnumerator())
                {
                    while (index >= 0 && enumerator.MoveNext())
                    {
                        index--;
                    }
                    if (index == -1)
                    {
                        child = enumerator.Current;
                        return(true);
                    }
                }
            }

            // If no child was found then return false.
            child = default(T);
            return(false);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Determines if a node has children.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">
        /// The node being checked for children.
        /// </param>
        /// <returns>
        /// Returns a <see cref="System.Boolean"/> indicating whether or not the node has children.
        /// </returns>
        public static bool HasChildren <T>(this ITreeWalker <T> walker, T node)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            return(walker.GetChildren(node).Any());
        }
        /// <summary>
        /// Gets the degree of a node (number of children).
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">The node whose degree is to be returned.</param>
        /// <returns>The degree (number of children) of the node.</returns>
        public static int GetDegree <T>(this ITreeWalker <T> walker, T node)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Return the number of children the node has.
            return(walker.GetChildren(node).Count());
        }
        /// <summary>
        /// Gets a node's following siblings, i.e. all nodes that share the same parent and follow
        /// the node in the parent's list of children.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">
        /// The node whose siblings are to be returned.
        /// </param>
        /// <param name="comparer">
        /// An <see cref="System.Collections.Generic.IEqualityComparer&lt;T&gt;"/> that knows how
        /// to compare two nodes for equality.  This is used to make sure that
        /// <paramref name="node"/> is not returned in the resulting
        /// <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/>.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains the
        /// siblings.
        /// </returns>
        public static IEnumerable <T> GetFollowingSiblings <T>(this ITreeWalker <T> walker, T node, IEqualityComparer <T> comparer)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // If the comparer is null then use the default comparer.
            if (comparer == null)
            {
                comparer = EqualityComparer <T> .Default;
            }

            // Get the node's parent.
            T parent;

            if (walker.TryGetParent(node, out parent))
            {
                // Return all of the parent's children after the original node.
                using (IEnumerator <T> enumerator = walker.GetChildren(parent).GetEnumerator())
                {
                    while (enumerator.MoveNext() && !comparer.Equals(enumerator.Current, node))
                    {
                        ;
                    }

                    while (enumerator.MoveNext())
                    {
                        yield return(enumerator.Current);
                    }
                }
            }
            else
            {
                // If the node does not have a parent then return an empty IEnumerable.
                yield break;
            }
        }
        /// <summary>
        /// Gets a node's preceding siblings, i.e. all nodes that share the same parent and precede
        /// the node in the parent's list of children.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">
        /// The node whose siblings are to be returned.
        /// </param>
        /// <param name="comparer">
        /// An <see cref="System.Collections.Generic.IEqualityComparer&lt;T&gt;"/> that knows how
        /// to compare two nodes for equality.  This is used to make sure that
        /// <paramref name="node"/> is not returned in the resulting
        /// <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/>.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains the
        /// siblings.
        /// </returns>
        public static IEnumerable <T> GetPrecedingSiblings <T>(this ITreeWalker <T> walker, T node, IEqualityComparer <T> comparer)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // If the comparer is null then use the default comparer.
            if (comparer == null)
            {
                comparer = EqualityComparer <T> .Default;
            }

            // Get the node's parent.
            T parent;

            if (walker.TryGetParent(node, out parent))
            {
                // Return all of the parent's children up to (not not including) the original node.
                foreach (T child in walker.GetChildren(parent))
                {
                    if (comparer.Equals(child, node))
                    {
                        yield break;
                    }
                    else
                    {
                        yield return(child);
                    }
                }
            }
            else
            {
                // If the node does not have a parent then return an empty IEnumerable.
                yield break;
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Gets the children that match the <paramref name="key"/>.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="nodes">
        /// The root nodes to be queried.
        /// </param>
        /// <param name="key">
        /// The key that each child will be compared to.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// matching children.
        /// </returns>
        public static IEnumerable <T> GetChildren <T>(
            this ITreeWalker <T> walker,
            IEnumerable <T> nodes,
            T key)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            return(walker.GetChildren(nodes, key, null));
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Gets all branches of a tree; a branch being a path from the root node to
        /// a leaf node.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="node">
        /// The node that all branches will start from.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;System.Collections.Generic.IList&lt;T&gt;&gt;"/>
        /// that contains all the branches.
        /// </returns>
        public static IEnumerable <IList <T> > GetBranches <T>(
            this ITreeWalker <T> walker,
            T node)
        {
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to keep track of the branches being traversed.
            Stack <IEnumerator <T> > enumerators = new Stack <IEnumerator <T> >();

            enumerators.Push(Enumerable.Repeat(node, 1).GetEnumerator());

            // Loop as long as there are enumerators on the stack.
            while (enumerators.Count > 0)
            {
                // Push enumerators onto the stack until we push an empty enumerator onto the
                // stack.  This is how we construct a branch.
                while (enumerators.Peek().MoveNext())
                {
                    enumerators
                    .Push(
                        walker
                        .GetChildren(
                            enumerators
                            .Peek()
                            .Current)
                        .GetEnumerator());
                }

                // The top enumerator does not have any items; pop it off the stack and yield the
                // current item from each enumerator on the stack in reverse.  This is a branch.
                enumerators.Pop().Dispose();
                yield return(enumerators.ToReverseArray(x => x.Current));

                // Pop enumerators off the stack until the stack is empty or we get to an
                // enumerator that has a next item.
                while (enumerators.Count > 0 && !enumerators.Peek().MoveNext())
                {
                    enumerators.Pop().Dispose();
                }

                // If there is an enumerator on the stack then get the children of the enumerators
                // current item and push the enumerator of the children onto the stack.  We are
                // ready to start building the next branch.
                if (enumerators.Count > 0)
                {
                    enumerators
                    .Push(
                        walker
                        .GetChildren(
                            enumerators
                            .Peek()
                            .Current)
                        .GetEnumerator());
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Enumerates a tree using the level-order traversal method. I.e. it
        /// returns all nodes in the first level relative to the specified node,
        /// followed by all nodes in the second level, etc...
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the
        /// parent and child nodes.
        /// </param>
        /// <param name="node">
        /// The root node of the tree that is to be traversed.
        /// </param>
        /// <param name="excludeSubtreePredicate">
        /// A <see cref="System.Func&lt;T, int, bool&gt;"/> that determines if
        /// the current node that is being evaluated (and all of its descendants)
        /// should be included in the traversal. This allows for short-circuiting
        /// of the level-order traversal by excluding particular subtrees from
        /// the traversal. The first argument is the current node being evaluated
        /// and the second argument is the depth of the current node relative to
        /// the original node that the traversal began on.
        /// </param>
        /// <param name="excludeOption">
        /// Used in conjunction with the <paramref
        /// name="excludeSubtreePredicate"/>. Determines if the entire subtree
        /// should be excluded or just its children.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that
        /// contains all the nodes in the tree ordered based on a level-order
        /// traversal.
        /// </returns>
        public static IEnumerable <T> LevelOrderTraversal <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, int, bool> excludeSubtreePredicate,
            ExcludeOption excludeOption)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Set the initial depth to 0.
            int depth = 0;

            // Set 'node' as the current level.
            List <IEnumerable <T> > currentLevel = new List <IEnumerable <T> >()
            {
                new T[] { node }
            };
            List <IEnumerable <T> > nextLevel = new List <IEnumerable <T> >();

            // Track whether the current level has any nodes. This is true
            // initially since the current level is simply the node that was
            // passed to this function.
            bool currentLevelHasNodes = true;

            // Enumerate 'currentLevel' and yield each node while adding that
            // node's children to 'nextLevel'. When complete: set 'currentLevel'
            // equal to 'nextLevel', increment 'depth' and repeat the process.
            while (currentLevelHasNodes)
            {
                // Set current level has nodes to false when we enter the loop.
                // This will be set to true again if any nodes are concatenated
                // to 'nextLevel'.
                currentLevelHasNodes = false;
                foreach (T currentNode in currentLevel.SelectMany(x => x))
                {
                    // If the 'excludeSubtreePredicate' is not null and evaluates
                    // to true then exlucude this node and all of its
                    // descendants, depending on 'excludeOption', from the
                    // traversal result.
                    if (excludeSubtreePredicate != null && excludeSubtreePredicate.Invoke(currentNode, depth))
                    {
                        if (excludeOption == ExcludeOption.ExcludeDescendants)
                        {
                            yield return(currentNode);
                        }
                    }
                    else
                    {
                        yield return(currentNode);

                        nextLevel.Add(walker.GetChildren(currentNode));
                        currentLevelHasNodes = true;
                    }
                }

                // Swap the lists. I am reusing lists rather than simply creating
                // a new empty list so that there are fewer objects to be garbage
                // collected.
                var temp = currentLevel;
                currentLevel = nextLevel;
                nextLevel    = temp;
                nextLevel.Clear();

                // Increment the depth counter.
                depth++;
            }
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Enumerates a tree using the post-order traversal method.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">The root node of the tree that is to be traversed.</param>
        /// <param name="excludeSubtreePredicate">
        /// A <see cref="System.Func&lt;T, Int32, Boolean&gt;"/> that determines if the current node
        /// that is being evaluated (and all of its descendants) should be included in the
        /// traversal.  This allows for short-circuiting of the post-order traversal by excluding
        /// particular subtrees from the traversal.  The first argument is the current node being
        /// evaluated and the second argument is the depth of the current node relative to the
        /// original node that the traversal began on.
        /// </param>
        /// <param name="excludeOption">
        /// Used in conjunction with the <paramref name="excludeSubtreePredicate"/>.  Determines
        /// if the entire subtree should be excluded or just its children.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// nodes in the tree ordered based on a post-order traversal.
        /// </returns>
        public static IEnumerable <T> PostOrderTraversal <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, int, bool> excludeSubtreePredicate,
            ExcludeOption excludeOption)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to keep track of the branches being traversed.
            Stack <IEnumerator <T> > enumerators = new Stack <IEnumerator <T> >();

            enumerators.Push(Enumerable.Repeat(node, 1).GetEnumerator());

            // Loop as long as we have an enumerator on the stack.  When we have popped the last
            // one off the stack the traversal is complete.
            while (enumerators.Count > 0)
            {
                if (enumerators.Peek().MoveNext())
                {
                    node = enumerators.Peek().Current;

                    // If the 'excludeSubtreePredicate' is not null and evaluates to true then
                    // yield the current node if 'excludeOption' is set to exclude the children.
                    // Otherwise, do not yield anything.
                    if (excludeSubtreePredicate != null && excludeSubtreePredicate.Invoke(node, enumerators.Count - 1))
                    {
                        if (excludeOption == ExcludeOption.ExcludeDescendants)
                        {
                            yield return(node);
                        }
                    }
                    else
                    {
                        // Push the current node's children onto the stack.
                        enumerators.Push(walker.GetChildren(node).GetEnumerator());
                    }
                }
                else
                {
                    // Pop the enumerator and dispose of it.
                    enumerators.Pop().Dispose();

                    // Yield the 'Current' value of the enumerator on the top of the stack.
                    if (enumerators.Count > 0)
                    {
                        yield return(enumerators.Peek().Current);
                    }
                }
            }

            //// If the 'excludeSubtreePredicate' is not null and evaluates to true then return
            //// 'node' or return an empty collection, depending on 'excludeOption'.
            //if (excludeSubtreePredicate != null && excludeSubtreePredicate.Invoke(node, 0))
            //{
            //    if (excludeOption == ExcludeOption.ExcludeDescendants)
            //    {
            //        yield return node;
            //    }
            //    yield break;
            //}
            //else
            //{
            //    // Create stacks to keep track of the branches being traversed.
            //    Stack<IEnumerator<T>> enumerators = new Stack<IEnumerator<T>>();
            //    Stack<T> nodes = new Stack<T>();

            //    // Push the current node and its children onto the stacks.
            //    nodes.Push(node);
            //    enumerators.Push(walker.GetChildren(node).GetEnumerator());

            //    // Loop as long as we have a node on the stack.  When we have popped the last node
            //    // off the stack the traversal is complete.
            //    while (nodes.Count > 0)
            //    {
            //        // Try and move to the current node's next child.
            //        if (enumerators.Peek().MoveNext())
            //        {
            //            // If we successfully moved to the next child then set the current node
            //            // to that child.
            //            node = enumerators.Peek().Current;

            //            // If the 'excludeSubtreePredicate' is not null and evaluates to true then
            //            // return yield the current node if 'excludeOption' is set to exclude the
            //            // children.  Otherwise, do not yield anything.
            //            if (excludeSubtreePredicate != null &&
            //                excludeSubtreePredicate.Invoke(node, nodes.Count))
            //            {
            //                if (excludeOption == ExcludeOption.ExcludeDescendants)
            //                {
            //                    yield return node;
            //                }
            //            }
            //            else
            //            {
            //                // Push the current node and its children onto the stacks.
            //                nodes.Push(node);
            //                enumerators.Push(walker.GetChildren(node).GetEnumerator());
            //            }
            //        }
            //        else
            //        {
            //            // If the current node does not have any more children then pop it off of
            //            // the 'nodes' stack and pop its children enumerator off the 'enumerators'
            //            // stack.
            //            // Yield the node that was popped off the stack.
            //            enumerators.Pop().Dispose();
            //            yield return nodes.Pop();
            //        }
            //    }
            //}
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Gets the nearest descendants based on a predicate.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child
        /// nodes.
        /// </param>
        /// <param name="nodes">
        /// The root nodes to be queried.
        /// </param>
        /// <param name="predicate">
        /// A predicate to test each node for selection.  The first argument is the current node
        /// being evaluated and the second argument is the depth of the current node relative to
        /// the original node that the query began on.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// matching nodes in the tree ordered based on a pre-order traversal.
        /// </returns>
        public static IEnumerable <T> GetDescendants <T>(
            this ITreeWalker <T> walker,
            IEnumerable <T> nodes,
            Func <T, int, bool> predicate)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }

            if (predicate == null)
            {
                throw new ArgumentNullException("predicate");
            }

            // Create a stack to keep track of the branches being traversed.
            Stack <IEnumerator <T> > enumerators = new Stack <IEnumerator <T> >();

            foreach (T node in nodes)
            {
                enumerators
                .Push(
                    walker
                    .GetChildren(node)
                    .GetEnumerator());

                while (enumerators.Count > 0)
                {
                    // Try and move to the current node's next child.
                    if (enumerators.Peek().MoveNext())
                    {
                        // If we successfully moved to the next child then set the current node
                        // to that child.
                        T currentNode = enumerators.Peek().Current;

                        // If the predicate evaluates to true then yield the current node.
                        // Otherwise, push the node and its enumerator to the stacks.
                        if (predicate(currentNode, enumerators.Count))
                        {
                            yield return(currentNode);
                        }
                        else
                        {
                            enumerators
                            .Push(
                                walker
                                .GetChildren(currentNode)
                                .GetEnumerator());
                        }
                    }
                    else
                    {
                        // If the current node does not have any more children then pop it off of
                        // the 'nodes' stack and pop its children enumerator off the 'enumerators'
                        // stack.
                        enumerators.Pop().Dispose();
                    }
                }
            }
        }