TreeExtensions.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. namespace Masuit.Tools.Models
  6. {
  7. /// <summary>
  8. /// 树形数据扩展
  9. /// </summary>
  10. public static class TreeExtensions
  11. {
  12. /// <summary>
  13. /// 过滤
  14. /// </summary>
  15. /// <typeparam name="T"></typeparam>
  16. /// <param name="items"></param>
  17. /// <param name="func"></param>
  18. /// <returns></returns>
  19. public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Func<T, bool> func) where T : class, ITreeChildren<T>
  20. {
  21. var results = new List<T>();
  22. foreach (var item in items.Where(i => i != null))
  23. {
  24. item.Children ??= new List<T>();
  25. item.Children = item.Children.Filter(func).ToList();
  26. if (item.Children.Any() || func(item))
  27. {
  28. results.Add(item);
  29. }
  30. }
  31. return results;
  32. }
  33. /// <summary>
  34. /// 过滤
  35. /// </summary>
  36. /// <typeparam name="T"></typeparam>
  37. /// <param name="items"></param>
  38. /// <param name="func"></param>
  39. /// <returns></returns>
  40. public static IEnumerable<Tree<T>> Filter<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, bool> func) where T : class
  41. {
  42. var results = new List<Tree<T>>();
  43. foreach (var item in items.Where(i => i != null))
  44. {
  45. item.Children ??= new List<Tree<T>>();
  46. item.Children = item.Children.Filter(func).ToList();
  47. if (item.Children.Any() || func(item))
  48. {
  49. results.Add(item);
  50. }
  51. }
  52. return results;
  53. }
  54. /// <summary>
  55. /// 过滤
  56. /// </summary>
  57. /// <typeparam name="T"></typeparam>
  58. /// <param name="item"></param>
  59. /// <param name="func"></param>
  60. /// <returns></returns>
  61. public static IEnumerable<T> Filter<T>(this T item, Func<T, bool> func) where T : class, ITreeChildren<T>
  62. {
  63. return new[] { item }.Filter(func);
  64. }
  65. /// <summary>
  66. /// 过滤
  67. /// </summary>
  68. /// <typeparam name="T"></typeparam>
  69. /// <param name="item"></param>
  70. /// <param name="func"></param>
  71. /// <returns></returns>
  72. public static IEnumerable<Tree<T>> Filter<T>(this Tree<T> item, Func<Tree<T>, bool> func) where T : class
  73. {
  74. return new[] { item }.Filter(func);
  75. }
  76. /// <summary>
  77. /// 平铺开
  78. /// </summary>
  79. /// <typeparam name="T"></typeparam>
  80. /// <param name="items"></param>
  81. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  82. /// <returns></returns>
  83. public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
  84. {
  85. var result = new List<T>();
  86. foreach (var item in items)
  87. {
  88. result.Add(item);
  89. item.Children ??= new List<T>();
  90. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  91. result.AddRange(item.Children.Flatten(optionAction));
  92. }
  93. return result;
  94. }
  95. /// <summary>
  96. /// 平铺开
  97. /// </summary>
  98. /// <typeparam name="T"></typeparam>
  99. /// <param name="p"></param>
  100. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  101. /// <returns></returns>
  102. public static IEnumerable<T> Flatten<T>(this T p, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
  103. {
  104. var result = new List<T>()
  105. {
  106. p
  107. };
  108. foreach (var item in p.Children)
  109. {
  110. result.Add(item);
  111. item.Children ??= new List<T>();
  112. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  113. result.AddRange(item.Children.Flatten());
  114. }
  115. return result;
  116. }
  117. /// <summary>
  118. /// 平铺开任意树形结构数据
  119. /// </summary>
  120. /// <typeparam name="T"></typeparam>
  121. /// <param name="items"></param>
  122. /// <param name="selector"></param>
  123. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  124. /// <returns></returns>
  125. public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector, Action<T, T> optionAction = null)
  126. {
  127. var result = new List<T>();
  128. foreach (var item in items)
  129. {
  130. result.Add(item);
  131. selector(item).ForEach(c => optionAction?.Invoke(c, item));
  132. result.AddRange(selector(item).Flatten(selector));
  133. }
  134. return result;
  135. }
  136. /// <summary>
  137. /// 平铺开
  138. /// </summary>
  139. /// <typeparam name="T"></typeparam>
  140. /// <param name="items"></param>
  141. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  142. /// <returns></returns>
  143. public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
  144. {
  145. var result = new List<Tree<T>>();
  146. foreach (var item in items)
  147. {
  148. result.Add(item);
  149. item.Children ??= new List<Tree<T>>();
  150. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  151. result.AddRange(item.Children.Flatten());
  152. }
  153. return result;
  154. }
  155. /// <summary>
  156. /// 平铺开
  157. /// </summary>
  158. /// <typeparam name="T"></typeparam>
  159. /// <param name="p"></param>
  160. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  161. /// <returns></returns>
  162. public static IEnumerable<Tree<T>> Flatten<T>(this Tree<T> p, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
  163. {
  164. var result = new List<Tree<T>>()
  165. {
  166. p
  167. };
  168. foreach (var item in p.Children)
  169. {
  170. result.Add(item);
  171. item.Children ??= new List<Tree<T>>();
  172. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  173. result.AddRange(item.Children.Flatten());
  174. }
  175. return result;
  176. }
  177. /// <summary>
  178. /// 平铺开任意树形结构数据
  179. /// </summary>
  180. /// <typeparam name="T"></typeparam>
  181. /// <param name="items"></param>
  182. /// <param name="selector"></param>
  183. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  184. /// <returns></returns>
  185. public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, IEnumerable<Tree<T>>> selector, Action<Tree<T>, Tree<T>> optionAction = null)
  186. {
  187. var result = new List<Tree<T>>();
  188. foreach (var item in items)
  189. {
  190. result.Add(item);
  191. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  192. result.AddRange(selector(item).Flatten(selector));
  193. }
  194. return result;
  195. }
  196. /// <summary>
  197. /// 平行集合转换成树形结构
  198. /// </summary>
  199. /// <typeparam name="T"></typeparam>
  200. /// <param name="source"></param>
  201. /// <param name="idSelector"></param>
  202. /// <param name="pidSelector"></param>
  203. /// <param name="topValue">根对象parentId的值</param>
  204. /// <returns></returns>
  205. public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, string>> idSelector, Expression<Func<T, string>> pidSelector, string topValue = default) where T : ITreeParent<T>, ITreeChildren<T>
  206. {
  207. return ToTree<T, string>(source, idSelector, pidSelector, topValue);
  208. }
  209. /// <summary>
  210. /// 平行集合转换成树形结构
  211. /// </summary>
  212. /// <typeparam name="T"></typeparam>
  213. /// <param name="source"></param>
  214. /// <param name="idSelector"></param>
  215. /// <param name="pidSelector"></param>
  216. /// <param name="topValue">根对象parentId的值</param>
  217. /// <returns></returns>
  218. public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, int>> idSelector, Expression<Func<T, int>> pidSelector, int topValue = 0) where T : ITreeParent<T>, ITreeChildren<T>
  219. {
  220. return ToTree<T, int>(source, idSelector, pidSelector, topValue);
  221. }
  222. /// <summary>
  223. /// 平行集合转换成树形结构
  224. /// </summary>
  225. /// <typeparam name="T"></typeparam>
  226. /// <param name="source"></param>
  227. /// <param name="idSelector"></param>
  228. /// <param name="pidSelector"></param>
  229. /// <param name="topValue">根对象parentId的值</param>
  230. /// <returns></returns>
  231. public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, long>> idSelector, Expression<Func<T, long>> pidSelector, long topValue = 0) where T : ITreeParent<T>, ITreeChildren<T>
  232. {
  233. return ToTree<T, long>(source, idSelector, pidSelector, topValue);
  234. }
  235. /// <summary>
  236. /// 平行集合转换成树形结构
  237. /// </summary>
  238. /// <typeparam name="T"></typeparam>
  239. /// <param name="source"></param>
  240. /// <param name="idSelector"></param>
  241. /// <param name="pidSelector"></param>
  242. /// <param name="topValue">根对象parentId的值</param>
  243. /// <returns></returns>
  244. public static List<T> ToTree<T>(this IEnumerable<T> source, Expression<Func<T, Guid>> idSelector, Expression<Func<T, Guid>> pidSelector, Guid topValue = default) where T : ITreeParent<T>, ITreeChildren<T>
  245. {
  246. return ToTree<T, Guid>(source, idSelector, pidSelector, topValue);
  247. }
  248. /// <summary>
  249. /// 平行集合转换成树形结构
  250. /// </summary>
  251. /// <typeparam name="T"></typeparam>
  252. /// <typeparam name="TKey"></typeparam>
  253. /// <param name="source"></param>
  254. /// <param name="idSelector"></param>
  255. /// <param name="pidSelector"></param>
  256. /// <param name="topValue">根对象parentId的值</param>
  257. /// <returns></returns>
  258. public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey>> pidSelector, TKey topValue = default) where T : ITreeParent<T>, ITreeChildren<T> where TKey : IComparable
  259. {
  260. if (idSelector.Body.ToString() == pidSelector.Body.ToString())
  261. {
  262. throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
  263. }
  264. var pidFunc = pidSelector.Compile();
  265. var idFunc = idSelector.Compile();
  266. source = source.Where(t => t != null);
  267. var temp = new List<T>();
  268. foreach (var item in source.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
  269. {
  270. item.Parent = default;
  271. TransData(source, item, idFunc, pidFunc);
  272. temp.Add(item);
  273. }
  274. return temp;
  275. }
  276. private static void TransData<T, TKey>(IEnumerable<T> source, T parent, Func<T, TKey> idSelector, Func<T, TKey> pidSelector) where T : ITreeParent<T>, ITreeChildren<T> where TKey : IComparable
  277. {
  278. var temp = new List<T>();
  279. foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent)) == true))
  280. {
  281. TransData(source, item, idSelector, pidSelector);
  282. item.Parent = parent;
  283. temp.Add(item);
  284. }
  285. parent.Children = temp;
  286. }
  287. /// <summary>
  288. /// 平行集合转换成树形结构
  289. /// </summary>
  290. /// <typeparam name="T"></typeparam>
  291. /// <typeparam name="TKey"></typeparam>
  292. /// <param name="source"></param>
  293. /// <param name="idSelector"></param>
  294. /// <param name="pidSelector"></param>
  295. /// <param name="topValue">根对象parentId的值</param>
  296. /// <returns></returns>
  297. public static List<Tree<T>> ToTreeGeneral<T, TKey>(this IEnumerable<T> source, Expression<Func<T, TKey>> idSelector, Expression<Func<T, TKey>> pidSelector, TKey topValue = default) where TKey : IComparable
  298. {
  299. if (idSelector.Body.ToString() == pidSelector.Body.ToString())
  300. {
  301. throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
  302. }
  303. var pidFunc = pidSelector.Compile();
  304. var idFunc = idSelector.Compile();
  305. source = source.Where(t => t != null);
  306. var temp = new List<Tree<T>>();
  307. foreach (var item in source.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
  308. {
  309. var parent = new Tree<T>(item);
  310. TransData(source, parent, idFunc, pidFunc);
  311. temp.Add(parent);
  312. }
  313. return temp;
  314. }
  315. private static void TransData<T, TKey>(IEnumerable<T> source, Tree<T> parent, Func<T, TKey> idSelector, Func<T, TKey> pidSelector) where TKey : IComparable
  316. {
  317. var temp = new List<Tree<T>>();
  318. foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent.Value)) == true))
  319. {
  320. var p = new Tree<T>(item);
  321. TransData(source, p, idSelector, pidSelector);
  322. p.Parent = parent.Value;
  323. temp.Add(p);
  324. }
  325. parent.Children = temp;
  326. }
  327. /// <summary>
  328. /// 所有子级
  329. /// </summary>
  330. public static ICollection<T> AllChildren<T>(this T tree) where T : ITreeChildren<T> => GetChildren(tree, c => c.Children);
  331. /// <summary>
  332. /// 所有子级
  333. /// </summary>
  334. public static ICollection<T> AllChildren<T>(this T tree, Func<T, IEnumerable<T>> selector) where T : ITreeChildren<T> => GetChildren(tree, selector);
  335. /// <summary>
  336. /// 所有子级
  337. /// </summary>
  338. public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree) => GetChildren(tree, c => c.Children);
  339. /// <summary>
  340. /// 所有子级
  341. /// </summary>
  342. public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree, Func<Tree<T>, IEnumerable<Tree<T>>> selector) => GetChildren(tree, selector);
  343. /// <summary>
  344. /// 所有父级
  345. /// </summary>
  346. public static ICollection<T> AllParent<T>(this T tree) where T : ITreeParent<T> => GetParents(tree, c => c.Parent);
  347. /// <summary>
  348. /// 所有父级
  349. /// </summary>
  350. public static ICollection<T> AllParent<T>(this T tree, Func<T, T> selector) where T : ITreeParent<T> => GetParents(tree, selector);
  351. /// <summary>
  352. /// 所有父级
  353. /// </summary>
  354. public static ICollection<Tree<T>> AllParent<T>(this Tree<T> tree, Func<Tree<T>, Tree<T>> selector) => GetParents(tree, selector);
  355. /// <summary>
  356. /// 是否是根节点
  357. /// </summary>
  358. public static bool IsRoot<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => tree.Parent == null;
  359. /// <summary>
  360. /// 是否是叶子节点
  361. /// </summary>
  362. public static bool IsLeaf<T>(this ITreeChildren<T> tree) where T : ITreeChildren<T> => tree.Children?.Count == 0;
  363. /// <summary>
  364. /// 是否是根节点
  365. /// </summary>
  366. public static bool IsRoot<T>(this Tree<T> tree) => tree.Parent == null;
  367. /// <summary>
  368. /// 是否是叶子节点
  369. /// </summary>
  370. public static bool IsLeaf<T>(this Tree<T> tree) => tree.Children?.Count == 0;
  371. /// <summary>
  372. /// 深度层级
  373. /// </summary>
  374. public static int Level<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => IsRoot(tree) ? 1 : Level(tree.Parent) + 1;
  375. /// <summary>
  376. /// 节点路径(UNIX路径格式,以“/”分隔)
  377. /// </summary>
  378. public static string Path<T>(this T tree) where T : ITree<T> => GetFullPath(tree, t => t.Name);
  379. /// <summary>
  380. /// 节点路径(UNIX路径格式,以“/”分隔)
  381. /// </summary>
  382. public static string Path<T>(this T tree, Func<T, string> selector) where T : ITreeParent<T> => GetFullPath(tree, selector);
  383. /// <summary>
  384. /// 根节点
  385. /// </summary>
  386. public static T Root<T>(this T tree) where T : ITreeParent<T> => GetRoot(tree, t => t.Parent);
  387. 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);
  388. /// <summary>
  389. /// 根节点
  390. /// </summary>
  391. public static T GetRoot<T>(T c, Func<T, T> selector) where T : ITreeParent<T> => c.Parent != null ? GetRoot(c.Parent, selector) : c;
  392. /// <summary>
  393. /// 递归取出所有下级
  394. /// </summary>
  395. /// <param name="t"></param>
  396. /// <returns></returns>
  397. private static List<T> GetChildren<T>(T t, Func<T, IEnumerable<T>> selector)
  398. {
  399. return selector(t).Union(selector(t).Where(c => selector(c).Any()).SelectMany(c => GetChildren(c, selector))).ToList();
  400. }
  401. /// <summary>
  402. /// 递归取出所有上级
  403. /// </summary>
  404. /// <param name="t"></param>
  405. /// <returns></returns>
  406. private static List<T> GetParents<T>(T t, Func<T, T> selector)
  407. {
  408. var list = new List<T>() { selector(t) };
  409. if (selector(t) != null)
  410. {
  411. return list.Union(GetParents(selector(t), selector)).Where(x => x != null).ToList();
  412. }
  413. list.RemoveAll(x => x == null);
  414. return list;
  415. }
  416. }
  417. }