TreeExtensions.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. namespace Masuit.Tools.Models
  5. {
  6. /// <summary>
  7. /// 树形数据扩展
  8. /// </summary>
  9. public static class TreeExtensions
  10. {
  11. /// <summary>
  12. /// 过滤
  13. /// </summary>
  14. /// <typeparam name="T"></typeparam>
  15. /// <param name="items"></param>
  16. /// <param name="func"></param>
  17. /// <returns></returns>
  18. public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Func<T, bool> func) where T : class, ITreeChildren<T>
  19. {
  20. var results = new List<T>();
  21. foreach (var item in items.Where(i => i != null))
  22. {
  23. item.Children ??= new List<T>();
  24. item.Children = item.Children.Filter(func).ToList();
  25. if (item.Children.Any() || func(item))
  26. {
  27. results.Add(item);
  28. }
  29. }
  30. return results;
  31. }
  32. /// <summary>
  33. /// 过滤
  34. /// </summary>
  35. /// <typeparam name="T"></typeparam>
  36. /// <param name="item"></param>
  37. /// <param name="func"></param>
  38. /// <returns></returns>
  39. public static IEnumerable<T> Filter<T>(this T item, Func<T, bool> func) where T : class, ITreeChildren<T>
  40. {
  41. return new[] { item }.Filter(func);
  42. }
  43. /// <summary>
  44. /// 平铺开
  45. /// </summary>
  46. /// <typeparam name="T"></typeparam>
  47. /// <param name="items"></param>
  48. /// <returns></returns>
  49. public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items) where T : class, ITreeChildren<T>
  50. {
  51. var result = new List<T>();
  52. foreach (var item in items)
  53. {
  54. result.Add(item);
  55. item.Children ??= new List<T>();
  56. result.AddRange(item.Children.Flatten());
  57. }
  58. return result;
  59. }
  60. /// <summary>
  61. /// 平铺开
  62. /// </summary>
  63. /// <typeparam name="T"></typeparam>
  64. /// <returns></returns>
  65. public static IEnumerable<T> Flatten<T>(this T p) where T : class, ITreeChildren<T>
  66. {
  67. var result = new List<T>()
  68. {
  69. p
  70. };
  71. foreach (var item in p.Children)
  72. {
  73. result.Add(item);
  74. item.Children ??= new List<T>();
  75. result.AddRange(item.Children.Flatten());
  76. }
  77. return result;
  78. }
  79. /// <summary>
  80. /// 平铺开任意树形结构数据
  81. /// </summary>
  82. /// <typeparam name="T"></typeparam>
  83. /// <param name="items"></param>
  84. /// <param name="selector"></param>
  85. /// <returns></returns>
  86. public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
  87. {
  88. var result = new List<T>();
  89. foreach (var item in items)
  90. {
  91. result.Add(item);
  92. result.AddRange(selector(item).Flatten(selector));
  93. }
  94. return result;
  95. }
  96. /// <summary>
  97. /// 所有子级
  98. /// </summary>
  99. public static ICollection<T> AllChildren<T>(this T tree) where T : ITreeChildren<T> => GetChildren(tree, c => c.Children);
  100. /// <summary>
  101. /// 所有子级
  102. /// </summary>
  103. public static ICollection<T> AllChildren<T>(this T tree, Func<T, IEnumerable<T>> selector) => GetChildren(tree, selector);
  104. /// <summary>
  105. /// 所有父级
  106. /// </summary>
  107. public static ICollection<T> AllParent<T>(this T tree) where T : ITreeParent<T> => GetParents(tree, c => c.Parent);
  108. /// <summary>
  109. /// 所有父级
  110. /// </summary>
  111. public static ICollection<T> AllParent<T>(this T tree, Func<T, T> selector) => GetParents(tree, selector);
  112. /// <summary>
  113. /// 是否是根节点
  114. /// </summary>
  115. public static bool IsRoot<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => tree.Parent == null;
  116. /// <summary>
  117. /// 是否是叶子节点
  118. /// </summary>
  119. public static bool IsLeaf<T>(this ITreeChildren<T> tree) where T : ITreeChildren<T> => tree.Children?.Count == 0;
  120. /// <summary>
  121. /// 深度层级
  122. /// </summary>
  123. public static int Level<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => IsRoot(tree) ? 1 : Level(tree.Parent) + 1;
  124. /// <summary>
  125. /// 节点路径(UNIX路径格式,以“/”分隔)
  126. /// </summary>
  127. public static string Path<T>(this T tree) where T : ITree<T> => GetFullPath(tree, t => t.Name);
  128. /// <summary>
  129. /// 节点路径(UNIX路径格式,以“/”分隔)
  130. /// </summary>
  131. public static string Path<T>(this T tree, Func<T, string> selector) where T : ITreeParent<T> => GetFullPath(tree, selector);
  132. /// <summary>
  133. /// 根节点
  134. /// </summary>
  135. public static T Root<T>(this T tree) where T : ITreeParent<T> => GetRoot(tree, t => t.Parent);
  136. private static string GetFullPath<T>(T c, Func<T, string> selector) where T : ITreeParent<T> => c.Parent != null ? GetFullPath(c.Parent, selector) + "/" + selector(c) : selector(c);
  137. /// <summary>
  138. /// 根节点
  139. /// </summary>
  140. public static T GetRoot<T>(T c, Func<T, T> selector) where T : ITreeParent<T> => c.Parent != null ? GetRoot(c.Parent, selector) : c;
  141. /// <summary>
  142. /// 递归取出所有下级
  143. /// </summary>
  144. /// <param name="t"></param>
  145. /// <returns></returns>
  146. private static List<T> GetChildren<T>(T t, Func<T, IEnumerable<T>> selector)
  147. {
  148. return selector(t).Union(selector(t).Where(c => selector(c).Any()).SelectMany(c => GetChildren(c, selector))).ToList();
  149. }
  150. /// <summary>
  151. /// 递归取出所有上级
  152. /// </summary>
  153. /// <param name="t"></param>
  154. /// <returns></returns>
  155. private static List<T> GetParents<T>(T t, Func<T, T> selector)
  156. {
  157. var list = new List<T>() { selector(t) };
  158. if (selector(t) != null)
  159. {
  160. return list.Union(GetParents(selector(t), selector)).Where(x => x != null).ToList();
  161. }
  162. list.RemoveAll(x => x == null);
  163. return list;
  164. }
  165. }
  166. }