TreeExtensions.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using Masuit.Tools.Systems;
  6. namespace Masuit.Tools.Models
  7. {
  8. /// <summary>
  9. /// 树形数据扩展
  10. /// </summary>
  11. public static class TreeExtensions
  12. {
  13. /// <summary>
  14. /// 过滤
  15. /// </summary>
  16. /// <typeparam name="T"></typeparam>
  17. /// <param name="items"></param>
  18. /// <param name="func"></param>
  19. /// <returns></returns>
  20. public static IEnumerable<T> Filter<T>(this IEnumerable<T> items, Func<T, bool> func) where T : class, ITreeChildren<T>
  21. {
  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. yield return item;
  29. }
  30. }
  31. }
  32. /// <summary>
  33. /// 过滤
  34. /// </summary>
  35. /// <typeparam name="T"></typeparam>
  36. /// <param name="items"></param>
  37. /// <param name="func"></param>
  38. /// <returns></returns>
  39. public static IEnumerable<Tree<T>> Filter<T>(this IEnumerable<Tree<T>> items, Func<Tree<T>, bool> func) where T : class
  40. {
  41. foreach (var item in items.Where(i => i != null))
  42. {
  43. item.Children ??= new List<Tree<T>>();
  44. item.Children = item.Children.Filter(func).ToList();
  45. if (item.Children.Any() || func(item))
  46. {
  47. yield return item;
  48. }
  49. }
  50. }
  51. /// <summary>
  52. /// 过滤
  53. /// </summary>
  54. /// <typeparam name="T"></typeparam>
  55. /// <param name="item"></param>
  56. /// <param name="func"></param>
  57. /// <returns></returns>
  58. public static IEnumerable<T> Filter<T>(this T item, Func<T, bool> func) where T : class, ITreeChildren<T>
  59. {
  60. return new[] { item }.Filter(func);
  61. }
  62. /// <summary>
  63. /// 过滤
  64. /// </summary>
  65. /// <typeparam name="T"></typeparam>
  66. /// <param name="item"></param>
  67. /// <param name="func"></param>
  68. /// <returns></returns>
  69. public static IEnumerable<Tree<T>> Filter<T>(this Tree<T> item, Func<Tree<T>, bool> func) where T : class
  70. {
  71. return new[] { item }.Filter(func);
  72. }
  73. /// <summary>
  74. /// 平铺开
  75. /// </summary>
  76. /// <typeparam name="T"></typeparam>
  77. /// <param name="items"></param>
  78. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  79. /// <returns></returns>
  80. public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
  81. {
  82. foreach (var item in items)
  83. {
  84. yield return item;
  85. item.Children ??= new List<T>();
  86. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  87. foreach (var children in item.Children.Flatten(optionAction))
  88. {
  89. yield return children;
  90. }
  91. }
  92. }
  93. /// <summary>
  94. /// 平铺开
  95. /// </summary>
  96. /// <typeparam name="T"></typeparam>
  97. /// <param name="p"></param>
  98. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  99. /// <returns></returns>
  100. public static IEnumerable<T> Flatten<T>(this T p, Action<T, T> optionAction = null) where T : class, ITreeChildren<T>
  101. {
  102. yield return p;
  103. foreach (var item in p.Children)
  104. {
  105. yield return item;
  106. item.Children ??= new List<T>();
  107. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  108. foreach (var children in item.Children.Flatten())
  109. {
  110. yield return children;
  111. }
  112. }
  113. }
  114. /// <summary>
  115. /// 平铺开任意树形结构数据
  116. /// </summary>
  117. /// <typeparam name="T"></typeparam>
  118. /// <param name="items"></param>
  119. /// <param name="selector"></param>
  120. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  121. /// <returns></returns>
  122. public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector, Action<T, T> optionAction = null)
  123. {
  124. foreach (var item in items)
  125. {
  126. yield return item;
  127. selector(item).ForEach(c => optionAction?.Invoke(c, item));
  128. foreach (var children in selector(item).Flatten(selector))
  129. {
  130. yield return children;
  131. }
  132. }
  133. }
  134. /// <summary>
  135. /// 平铺开
  136. /// </summary>
  137. /// <typeparam name="T"></typeparam>
  138. /// <param name="items"></param>
  139. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  140. /// <returns></returns>
  141. public static IEnumerable<Tree<T>> Flatten<T>(this IEnumerable<Tree<T>> items, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
  142. {
  143. foreach (var item in items)
  144. {
  145. yield return item;
  146. item.Children ??= new List<Tree<T>>();
  147. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  148. foreach (var tree in item.Children.Flatten())
  149. {
  150. yield return tree;
  151. }
  152. }
  153. }
  154. /// <summary>
  155. /// 平铺开
  156. /// </summary>
  157. /// <typeparam name="T"></typeparam>
  158. /// <param name="p"></param>
  159. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  160. /// <returns></returns>
  161. public static IEnumerable<Tree<T>> Flatten<T>(this Tree<T> p, Action<Tree<T>, Tree<T>> optionAction = null) where T : class
  162. {
  163. yield return p;
  164. foreach (var item in p.Children)
  165. {
  166. yield return item;
  167. item.Children ??= new List<Tree<T>>();
  168. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  169. foreach (var tree in item.Children.Flatten())
  170. {
  171. yield return tree;
  172. }
  173. }
  174. }
  175. /// <summary>
  176. /// 平铺开任意树形结构数据
  177. /// </summary>
  178. /// <typeparam name="T"></typeparam>
  179. /// <param name="items"></param>
  180. /// <param name="selector"></param>
  181. /// <param name="optionAction">平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象</param>
  182. /// <returns></returns>
  183. 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)
  184. {
  185. foreach (var item in items)
  186. {
  187. yield return item;
  188. item.Children.ForEach(c => optionAction?.Invoke(c, item));
  189. foreach (var tree in selector(item).Flatten(selector))
  190. {
  191. yield return tree;
  192. }
  193. }
  194. }
  195. /// <summary>
  196. /// 平行集合转换成树形结构
  197. /// </summary>
  198. /// <typeparam name="T"></typeparam>
  199. /// <param name="source"></param>
  200. /// <param name="idSelector"></param>
  201. /// <param name="pidSelector"></param>
  202. /// <param name="topValue">根对象parentId的值</param>
  203. /// <returns></returns>
  204. 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>
  205. {
  206. return ToTree<T, string>(source, idSelector, pidSelector, topValue);
  207. }
  208. /// <summary>
  209. /// 平行集合转换成树形结构
  210. /// </summary>
  211. /// <typeparam name="T"></typeparam>
  212. /// <param name="source"></param>
  213. /// <param name="idSelector"></param>
  214. /// <param name="pidSelector"></param>
  215. /// <param name="topValue">根对象parentId的值</param>
  216. /// <returns></returns>
  217. 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>
  218. {
  219. return ToTree<T, int>(source, idSelector, pidSelector, topValue);
  220. }
  221. /// <summary>
  222. /// 平行集合转换成树形结构
  223. /// </summary>
  224. /// <typeparam name="T"></typeparam>
  225. /// <param name="source"></param>
  226. /// <param name="idSelector"></param>
  227. /// <param name="pidSelector"></param>
  228. /// <param name="topValue">根对象parentId的值</param>
  229. /// <returns></returns>
  230. 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>
  231. {
  232. return ToTree<T, long>(source, idSelector, pidSelector, topValue);
  233. }
  234. /// <summary>
  235. /// 平行集合转换成树形结构
  236. /// </summary>
  237. /// <typeparam name="T"></typeparam>
  238. /// <param name="source"></param>
  239. /// <param name="idSelector"></param>
  240. /// <param name="pidSelector"></param>
  241. /// <param name="topValue">根对象parentId的值</param>
  242. /// <returns></returns>
  243. 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>
  244. {
  245. return ToTree<T, Guid>(source, idSelector, pidSelector, topValue);
  246. }
  247. /// <summary>
  248. /// 平行集合转换成树形结构
  249. /// </summary>
  250. /// <typeparam name="T"></typeparam>
  251. /// <typeparam name="TKey"></typeparam>
  252. /// <param name="source"></param>
  253. /// <param name="idSelector"></param>
  254. /// <param name="pidSelector"></param>
  255. /// <param name="topValue">根对象parentId的值</param>
  256. /// <returns></returns>
  257. 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
  258. {
  259. if (source is IQueryable<T> queryable)
  260. {
  261. source = queryable.ToList();
  262. }
  263. if (idSelector.Body.ToString() == pidSelector.Body.ToString())
  264. {
  265. throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
  266. }
  267. var pidFunc = pidSelector.Compile();
  268. var idFunc = idSelector.Compile();
  269. return BuildTree(source.Where(t => t != null), idFunc, pidFunc, topValue).ToList();
  270. }
  271. /// <summary>
  272. /// 平行集合转换成树形结构
  273. /// </summary>
  274. /// <typeparam name="T"></typeparam>
  275. /// <param name="source"></param>
  276. /// <returns></returns>
  277. public static List<T> ToTree<T>(this IEnumerable<T> source) where T : ITreeEntity<T, int>
  278. {
  279. return ToTree<T, int>(source);
  280. }
  281. /// <summary>
  282. /// 平行集合转换成树形结构
  283. /// </summary>
  284. /// <typeparam name="T"></typeparam>
  285. /// <typeparam name="TKey"></typeparam>
  286. /// <param name="source"></param>
  287. /// <returns></returns>
  288. public static List<T> ToTree<T, TKey>(this IEnumerable<T> source, TKey? topValue = default) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable
  289. {
  290. if (source is IQueryable<T> queryable)
  291. {
  292. source = queryable.ToList();
  293. }
  294. source = source.Where(t => t != null).ToList();
  295. return BuildTree(source, topValue).ToList();
  296. }
  297. /// <summary>
  298. /// 平行集合转换成树形结构
  299. /// </summary>
  300. /// <typeparam name="T"></typeparam>
  301. /// <typeparam name="TKey"></typeparam>
  302. /// <param name="source"></param>
  303. /// <param name="idSelector"></param>
  304. /// <param name="pidSelector"></param>
  305. /// <param name="topValue">根对象parentId的值</param>
  306. /// <returns></returns>
  307. 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 : ITreeChildren<T> where TKey : struct
  308. {
  309. if (source is IQueryable<T> queryable)
  310. {
  311. source = queryable.ToList();
  312. }
  313. var pidFunc = pidSelector.Compile();
  314. var idFunc = idSelector.Compile();
  315. source = source.Where(t => t != null).ToList();
  316. return BuildTree(source, idFunc, pidFunc, topValue).ToList();
  317. }
  318. private static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, Func<T, TKey> idSelector, Func<T, TKey> pidSelector, TKey topValue = default) where T : ITreeChildren<T> where TKey : IComparable
  319. {
  320. // 创建一个字典,用于快速查找节点的子节点
  321. var childrenLookup = new Dictionary<TKey, List<T>>();
  322. foreach (var item in source.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
  323. {
  324. childrenLookup[idSelector(item)] = new List<T>();
  325. }
  326. // 构建树结构
  327. foreach (var item in source.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item))))
  328. {
  329. childrenLookup[pidSelector(item)].Add(item);
  330. }
  331. // 找到根节点,即没有父节点的节点
  332. foreach (var root in source.Where(x => Equals(pidSelector(x), topValue)))
  333. {
  334. // 为根节点和所有子节点设置Children属性
  335. // 使用队列来模拟递归过程
  336. var queue = new Queue<T>();
  337. queue.Enqueue(root);
  338. while (queue.Count > 0)
  339. {
  340. // 出队当前节点
  341. var current = queue.Dequeue();
  342. // 为当前节点设置子节点
  343. if (childrenLookup.TryGetValue(idSelector(current), out var children))
  344. {
  345. current.Children = children;
  346. foreach (var child in children)
  347. {
  348. // 如果子节点实现了ITreeParent接口,则设置其Parent属性
  349. if (child is ITreeParent<T> tree)
  350. {
  351. tree.Parent = current;
  352. }
  353. // 将子节点入队以继续处理
  354. queue.Enqueue(child);
  355. }
  356. }
  357. }
  358. yield return root;
  359. }
  360. }
  361. internal static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, TKey? topValue = default) where T : ITreeEntity<T, TKey> where TKey : struct, IComparable
  362. {
  363. // 创建一个字典,用于快速查找节点的子节点
  364. var childrenLookup = new NullableDictionary<TKey, List<T>>();
  365. foreach (var item in source.Where(item => !childrenLookup.ContainsKey(item.Id)))
  366. {
  367. childrenLookup[item.Id] = new List<T>();
  368. }
  369. // 构建树结构
  370. foreach (var item in source.Where(item => (item.ParentId != null || !Equals(item.ParentId, default(TKey))) && childrenLookup.ContainsKey(item.ParentId ?? default)))
  371. {
  372. childrenLookup[item.ParentId ?? default].Add(item);
  373. }
  374. // 找到根节点,即没有父节点的节点
  375. foreach (var root in source.Where(x => Equals(x.ParentId, topValue)))
  376. {
  377. // 为根节点和所有子节点设置Children属性
  378. // 使用队列来模拟递归过程
  379. var queue = new Queue<T>();
  380. queue.Enqueue(root);
  381. while (queue.Count > 0)
  382. {
  383. // 出队当前节点
  384. var current = queue.Dequeue();
  385. // 为当前节点设置子节点
  386. if (childrenLookup.TryGetValue(current.Id, out var children))
  387. {
  388. current.Children = children;
  389. foreach (var child in children)
  390. {
  391. // 如果子节点实现了ITreeParent接口,则设置其Parent属性
  392. if (child is ITreeParent<T> tree)
  393. {
  394. tree.Parent = current;
  395. }
  396. // 将子节点入队以继续处理
  397. queue.Enqueue(child);
  398. }
  399. }
  400. }
  401. yield return root;
  402. }
  403. }
  404. internal static IEnumerable<T> BuildTree<T>(IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T>
  405. {
  406. // 创建一个字典,用于快速查找节点的子节点
  407. var childrenLookup = new NullableDictionary<string, List<T>>();
  408. foreach (var item in source.Where(item => !childrenLookup.ContainsKey(item.Id)))
  409. {
  410. childrenLookup[item.Id] = new List<T>();
  411. }
  412. // 构建树结构
  413. foreach (var item in source.Where(item => !string.IsNullOrEmpty(item.ParentId) && childrenLookup.ContainsKey(item.ParentId)))
  414. {
  415. childrenLookup[item.ParentId].Add(item);
  416. }
  417. // 找到根节点,即没有父节点的节点
  418. foreach (var root in source.Where(x => Equals(x.ParentId, topValue)))
  419. {
  420. // 为根节点和所有子节点设置Children属性
  421. // 使用队列来模拟递归过程
  422. var queue = new Queue<T>();
  423. queue.Enqueue(root);
  424. while (queue.Count > 0)
  425. {
  426. // 出队当前节点
  427. var current = queue.Dequeue();
  428. // 为当前节点设置子节点
  429. if (childrenLookup.TryGetValue(current.Id, out var children))
  430. {
  431. current.Children = children;
  432. foreach (var child in children)
  433. {
  434. // 如果子节点实现了ITreeParent接口,则设置其Parent属性
  435. if (child is ITreeParent<T> tree)
  436. {
  437. tree.Parent = current;
  438. }
  439. // 将子节点入队以继续处理
  440. queue.Enqueue(child);
  441. }
  442. }
  443. }
  444. yield return root;
  445. }
  446. }
  447. private static IEnumerable<T> BuildTree<T, TKey>(IEnumerable<T> source, Func<T, TKey> idSelector, Func<T, TKey?> pidSelector, TKey? topValue = default) where T : ITreeChildren<T> where TKey : struct
  448. {
  449. // 创建一个字典,用于快速查找节点的子节点
  450. var childrenLookup = new NullableDictionary<TKey, List<T>>();
  451. foreach (var item in source.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
  452. {
  453. childrenLookup[idSelector(item)] = new List<T>();
  454. }
  455. // 构建树结构
  456. foreach (var item in source.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item) ?? default)))
  457. {
  458. childrenLookup[pidSelector(item) ?? default].Add(item);
  459. }
  460. // 找到根节点,即没有父节点的节点
  461. foreach (var root in source.Where(x => Equals(pidSelector(x), topValue)))
  462. {
  463. // 为根节点和所有子节点设置Children属性
  464. // 使用队列来模拟递归过程
  465. var queue = new Queue<T>();
  466. queue.Enqueue(root);
  467. while (queue.Count > 0)
  468. {
  469. // 出队当前节点
  470. var current = queue.Dequeue();
  471. // 为当前节点设置子节点
  472. if (childrenLookup.TryGetValue(idSelector(current), out var children))
  473. {
  474. current.Children = children;
  475. foreach (var child in children)
  476. {
  477. // 如果子节点实现了ITreeParent接口,则设置其Parent属性
  478. if (child is ITreeParent<T> tree)
  479. {
  480. tree.Parent = current;
  481. }
  482. // 将子节点入队以继续处理
  483. queue.Enqueue(child);
  484. }
  485. }
  486. }
  487. yield return root;
  488. }
  489. }
  490. /// <summary>
  491. /// 平行集合转换成树形结构
  492. /// </summary>
  493. /// <typeparam name="T"></typeparam>
  494. /// <typeparam name="TKey"></typeparam>
  495. /// <param name="source"></param>
  496. /// <param name="idSelector"></param>
  497. /// <param name="pidSelector"></param>
  498. /// <param name="topValue">根对象parentId的值</param>
  499. /// <returns></returns>
  500. 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
  501. {
  502. if (idSelector.Body.ToString() == pidSelector.Body.ToString())
  503. {
  504. throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
  505. }
  506. var pidFunc = pidSelector.Compile();
  507. var idFunc = idSelector.Compile();
  508. source = source.Where(t => t != null);
  509. var temp = new List<Tree<T>>();
  510. foreach (var item in source.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
  511. {
  512. var parent = new Tree<T>(item);
  513. BuildTree(source, parent, idFunc, pidFunc);
  514. temp.Add(parent);
  515. }
  516. return temp;
  517. }
  518. private static void BuildTree<T, TKey>(IEnumerable<T> source, Tree<T> parent, Func<T, TKey> idSelector, Func<T, TKey> pidSelector) where TKey : IComparable
  519. {
  520. var temp = new List<Tree<T>>();
  521. foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent.Value)) == true))
  522. {
  523. var p = new Tree<T>(item);
  524. BuildTree(source, p, idSelector, pidSelector);
  525. p.Parent = parent.Value;
  526. temp.Add(p);
  527. }
  528. parent.Children = temp;
  529. }
  530. /// <summary>
  531. /// 所有子级
  532. /// </summary>
  533. public static ICollection<T> AllChildren<T>(this T tree) where T : ITreeChildren<T> => GetChildren(tree, c => c.Children);
  534. /// <summary>
  535. /// 所有子级
  536. /// </summary>
  537. public static ICollection<T> AllChildren<T>(this T tree, Func<T, IEnumerable<T>> selector) where T : ITreeChildren<T> => GetChildren(tree, selector);
  538. /// <summary>
  539. /// 所有子级
  540. /// </summary>
  541. public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree) => GetChildren(tree, c => c.Children);
  542. /// <summary>
  543. /// 所有子级
  544. /// </summary>
  545. public static ICollection<Tree<T>> AllChildren<T>(this Tree<T> tree, Func<Tree<T>, IEnumerable<Tree<T>>> selector) => GetChildren(tree, selector);
  546. /// <summary>
  547. /// 所有父级
  548. /// </summary>
  549. public static ICollection<T> AllParent<T>(this T tree) where T : ITreeParent<T> => GetParents(tree, c => c.Parent);
  550. /// <summary>
  551. /// 所有父级
  552. /// </summary>
  553. public static ICollection<T> AllParent<T>(this T tree, Func<T, T> selector) where T : ITreeParent<T> => GetParents(tree, selector);
  554. /// <summary>
  555. /// 所有父级
  556. /// </summary>
  557. public static ICollection<Tree<T>> AllParent<T>(this Tree<T> tree, Func<Tree<T>, Tree<T>> selector) => GetParents(tree, selector);
  558. /// <summary>
  559. /// 是否是根节点
  560. /// </summary>
  561. public static bool IsRoot<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => tree.Parent == null;
  562. /// <summary>
  563. /// 是否是叶子节点
  564. /// </summary>
  565. public static bool IsLeaf<T>(this ITreeChildren<T> tree) where T : ITreeChildren<T> => tree.Children?.Count == 0;
  566. /// <summary>
  567. /// 是否是根节点
  568. /// </summary>
  569. public static bool IsRoot<T>(this Tree<T> tree) => tree.Parent == null;
  570. /// <summary>
  571. /// 是否是叶子节点
  572. /// </summary>
  573. public static bool IsLeaf<T>(this Tree<T> tree) => tree.Children?.Count == 0;
  574. /// <summary>
  575. /// 深度层级
  576. /// </summary>
  577. public static int Level<T>(this ITreeParent<T> tree) where T : ITreeParent<T> => IsRoot(tree) ? 1 : Level(tree.Parent) + 1;
  578. /// <summary>
  579. /// 节点路径(UNIX路径格式,以“/”分隔)
  580. /// </summary>
  581. public static string Path<T>(this T tree) where T : ITree<T> => GetFullPath(tree, t => t.Name);
  582. /// <summary>
  583. /// 节点路径(UNIX路径格式,以“/”分隔)
  584. /// </summary>
  585. public static string Path<T>(this T tree, Func<T, string> selector) where T : ITreeParent<T> => GetFullPath(tree, selector);
  586. /// <summary>
  587. /// 节点路径
  588. /// </summary>
  589. /// <param name="tree"></param>
  590. /// <param name="separator">分隔符</param>
  591. public static string Path<T>(this T tree, string separator) where T : ITree<T> => GetFullPath(tree, t => t.Name, separator);
  592. /// <summary>
  593. /// 节点路径
  594. /// </summary>
  595. /// <typeparam name="T"></typeparam>
  596. /// <param name="tree"></param>
  597. /// <param name="selector">选择字段</param>
  598. /// <param name="separator">分隔符</param>
  599. /// <returns></returns>
  600. public static string Path<T>(this T tree, Func<T, string> selector, string separator) where T : ITreeParent<T> => GetFullPath(tree, selector, separator);
  601. /// <summary>
  602. /// 根节点
  603. /// </summary>
  604. public static T Root<T>(this T tree) where T : ITreeParent<T> => GetRoot(tree, t => t.Parent);
  605. private static string GetFullPath<T>(T c, Func<T, string> selector, string separator = "/") where T : ITreeParent<T> => c.Parent != null ? GetFullPath(c.Parent, selector, separator) + separator + selector(c) : selector(c);
  606. /// <summary>
  607. /// 根节点
  608. /// </summary>
  609. public static T GetRoot<T>(T c, Func<T, T> selector) where T : ITreeParent<T> => c.Parent != null ? GetRoot(c.Parent, selector) : c;
  610. /// <summary>
  611. /// 递归取出所有下级
  612. /// </summary>
  613. /// <param name="t"></param>
  614. /// <param name="selector"></param>
  615. /// <returns></returns>
  616. private static List<T> GetChildren<T>(T t, Func<T, IEnumerable<T>> selector)
  617. {
  618. return selector(t).Union(selector(t).Where(c => selector(c)?.Any() == true).SelectMany(c => GetChildren(c, selector))).ToList();
  619. }
  620. /// <summary>
  621. /// 递归取出所有上级
  622. /// </summary>
  623. /// <param name="t"></param>
  624. /// <returns></returns>
  625. private static List<T> GetParents<T>(T t, Func<T, T> selector)
  626. {
  627. var list = new List<T>() { selector(t) };
  628. if (selector(t) != null)
  629. {
  630. return list.Union(GetParents(selector(t), selector)).Where(x => x != null).ToList();
  631. }
  632. list.RemoveAll(x => x == null);
  633. return list;
  634. }
  635. }
  636. public static class TreeExtensionLong
  637. {
  638. /// <summary>
  639. /// 平行集合转换成树形结构
  640. /// </summary>
  641. /// <typeparam name="T"></typeparam>
  642. /// <param name="source"></param>
  643. /// <returns></returns>
  644. public static List<T> ToTree<T>(this IEnumerable<T> source) where T : ITreeEntity<T, long>
  645. {
  646. return source.ToTree<T, long>();
  647. }
  648. }
  649. public static class TreeExtensionGuid
  650. {
  651. /// <summary>
  652. /// 平行集合转换成树形结构
  653. /// </summary>
  654. /// <typeparam name="T"></typeparam>
  655. /// <param name="source"></param>
  656. /// <returns></returns>
  657. public static List<T> ToTree<T>(this IEnumerable<T> source) where T : ITreeEntity<T, Guid>
  658. {
  659. return source.ToTree<T, Guid>();
  660. }
  661. }
  662. public static class TreeExtensionString
  663. {
  664. /// <summary>
  665. /// 平行集合转换成树形结构
  666. /// </summary>
  667. /// <typeparam name="T"></typeparam>
  668. /// <param name="source"></param>
  669. /// <param name="topValue"></param>
  670. /// <returns></returns>
  671. public static List<T> ToTree<T>(this IEnumerable<T> source, string topValue = null) where T : ITreeEntity<T>
  672. {
  673. if (source is IQueryable<T> queryable)
  674. {
  675. source = queryable.ToList();
  676. }
  677. source = source.Where(t => t != null).ToList();
  678. return TreeExtensions.BuildTree(source, topValue).ToList();
  679. }
  680. }
  681. }