TreeExtensions.cs 21 KB

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