using System; using System.Collections.Generic; using System.Linq; using System.Text; using RainmeterStudio.Core.Model; namespace RainmeterStudio.Core.Utils { /// /// Extension methods for trees /// public static class TreeExtensions { /// /// Tree traversal orders /// public enum TreeTraversalOrder { BreadthFirst, DepthFirst, DepthFirstPreOrder = DepthFirst, DepthFirstPostOrder } /// /// Traverses a tree /// /// Tree data type /// Root node of tree /// Traversal order /// An enumeration of the nodes in the specified traverse order public static IEnumerable> Traverse(this Tree root, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst) { if (order == TreeTraversalOrder.BreadthFirst) return TraverseBF(root); else return TraverseDF(root, order); } private static IEnumerable> TraverseDF(this Tree root, TreeTraversalOrder order) { // Preorder - return root first if (order == TreeTraversalOrder.DepthFirstPreOrder) yield return root; // Return children foreach (var child in root.Children) foreach (var node in TraverseDF(child, order)) yield return node; // Postorder - return root last if (order == TreeTraversalOrder.DepthFirstPostOrder) yield return root; } private static IEnumerable> TraverseBF(this Tree root) { // Create a queue containing the root Queue> queue = new Queue>(); queue.Enqueue(root); // While there are elements in the queue while (queue.Count > 0) { // Return next node in tree var node = queue.Dequeue(); yield return node; // Enqueue node's children foreach (var child in node.Children) queue.Enqueue(child); } } /// /// Applies an action to every node of the tree /// /// Tree data type /// Root node of tree /// Action to apply /// Traversal order public static void Apply(this Tree root, Action> action, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst) { // Safety check if (action == null) return; // Apply action foreach (var node in Traverse(root, order)) action(node); } /// /// Applies an action to every node of the tree /// /// Tree data type /// Root node of tree /// Action to apply /// Traversal order public static void ApplyToData(this Tree root, Action action, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst) where T : class { // Safety check if (action == null) return; // Apply action foreach (var node in Traverse(root, order)) action(node.Data); } /// /// Rebuilds the tree by applying the specified transform function /// /// Data type of tree /// Data type of rebuilt tree /// The root node /// The transform function /// The transformed tree public static Tree Transform(this Tree root, Func, Tree> transformFunction) { // Safety check if (transformFunction == null) throw new ArgumentNullException("Transform function cannot be null."); // Build root Tree resRoot = transformFunction(root); // Add children foreach (var node in root.Children) resRoot.Children.Add(Transform(node, transformFunction)); // Return return resRoot; } /// /// Rebuilds the tree by applying the specified transform function /// /// Data type of tree /// Data type of rebuilt tree /// The root node /// The transform function /// The transformed tree public static Tree TransformData(this Tree root, Func transformFunction) { // Safety check if (transformFunction == null) throw new ArgumentNullException("Transform function cannot be null."); // Build root Tree resRoot = new Tree(transformFunction(root.Data)); // Add children foreach (var node in root.Children) resRoot.Children.Add(TransformData(node, transformFunction)); // Return return resRoot; } } }