|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | + |
| 5 | + |
| 6 | +namespace Whathecode.System.Collections.Generic |
| 7 | +{ |
| 8 | + /// <summary> |
| 9 | + /// A collection of elements organized within a hierarchy. |
| 10 | + /// </summary> |
| 11 | + /// <typeparam name = "T">The type of the values in the dictionary.</typeparam> |
| 12 | + public class Tree<T> |
| 13 | + { |
| 14 | + public T Value; |
| 15 | + |
| 16 | + /// <summary> |
| 17 | + /// The parent to which this tree is connected. Null when this is a root. |
| 18 | + /// </summary> |
| 19 | + public Tree<T> Parent { get; private set; } |
| 20 | + |
| 21 | + readonly List<Tree<T>> _children = new List<Tree<T>>(); |
| 22 | + public IEnumerable<Tree<T>> Children |
| 23 | + { |
| 24 | + get { return _children; } |
| 25 | + } |
| 26 | + |
| 27 | + |
| 28 | + public Tree( T value ) |
| 29 | + { |
| 30 | + Value = value; |
| 31 | + } |
| 32 | + |
| 33 | + |
| 34 | + /// <summary> |
| 35 | + /// Adds a full branch to this tree, as specified by an ordered list of values. |
| 36 | + /// Existing branches (using the default Equals comparator) remain unchanged. |
| 37 | + /// </summary> |
| 38 | + /// <param name = "branch">The branch to add, ordered from the first branch after the root of this tree, to the final branch.</param> |
| 39 | + /// <returns>The first non-existing node of the branch which got added, or null when node already existed.</returns> |
| 40 | + public Tree<T> AddBranch( IEnumerable<T> branch ) |
| 41 | + { |
| 42 | + // Make sure the branch isn't empty. |
| 43 | + List<T> fullBranch = branch.ToList(); |
| 44 | + if ( fullBranch.Count == 0 ) |
| 45 | + { |
| 46 | + return null; |
| 47 | + } |
| 48 | + |
| 49 | + // Find matching leaf. |
| 50 | + T first = fullBranch.First(); |
| 51 | + Tree<T> matchingLeaf = _children.FirstOrDefault( c => c.Value.Equals( first ) ); |
| 52 | + if ( matchingLeaf == null ) |
| 53 | + { |
| 54 | + // Leaf doens't exist yet, create full remaining branch. |
| 55 | + Tree<T> firstNew = null; |
| 56 | + Tree<T> current = this; |
| 57 | + foreach ( var leaf in fullBranch ) |
| 58 | + { |
| 59 | + current = current.AddLeaf( leaf ); |
| 60 | + if ( firstNew == null ) |
| 61 | + { |
| 62 | + firstNew = current; |
| 63 | + } |
| 64 | + } |
| 65 | + return firstNew; |
| 66 | + } |
| 67 | + |
| 68 | + // Leafs match, go down the branch. |
| 69 | + return matchingLeaf.AddBranch( fullBranch.Skip( 1 ) ); |
| 70 | + } |
| 71 | + |
| 72 | + /// <summary> |
| 73 | + /// Adds a new leaf to this tree. |
| 74 | + /// </summary> |
| 75 | + /// <param name = "leaf">The value to add as a leaf to this tree.</param> |
| 76 | + /// <returns>The newly added leaf.</returns> |
| 77 | + public Tree<T> AddLeaf( T leaf ) |
| 78 | + { |
| 79 | + Tree<T> newLeaf = new Tree<T>( leaf ) { Parent = this }; |
| 80 | + _children.Add( newLeaf ); |
| 81 | + return newLeaf; |
| 82 | + } |
| 83 | + |
| 84 | + /// <summary> |
| 85 | + /// Traverses nodes up until the tree until a passed evaluation returns true. Null is returned when reaching the top of the tree. |
| 86 | + /// </summary> |
| 87 | + /// <param name = "stopTraversal">Function which evaluates whether to stop at a given node or not.</param> |
| 88 | + /// <returns>The first node encountered where <see cref="stopTraversal" /> returns true. Null in case the top of the tree is reached.</returns> |
| 89 | + public Tree<T> TraverseUpUntil( Func<Tree<T>, bool> stopTraversal ) |
| 90 | + { |
| 91 | + Tree<T> higherPeer = Parent; |
| 92 | + while ( higherPeer != null ) |
| 93 | + { |
| 94 | + if ( stopTraversal( higherPeer ) ) |
| 95 | + { |
| 96 | + break; |
| 97 | + } |
| 98 | + higherPeer = higherPeer.Parent; |
| 99 | + } |
| 100 | + |
| 101 | + return higherPeer; |
| 102 | + } |
| 103 | + |
| 104 | + /// <summary> |
| 105 | + /// Removes the current node from the parent tree. |
| 106 | + /// </summary> |
| 107 | + public void Remove() |
| 108 | + { |
| 109 | + Parent._children.Remove( this ); |
| 110 | + } |
| 111 | + } |
| 112 | +} |
0 commit comments