using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Masuit.Tools.Systems;
namespace Masuit.Tools.Models;
///
/// 树形数据扩展
///
public static class TreeExtensions
{
///
/// 过滤
///
///
///
///
///
public static IEnumerable Filter(this IEnumerable items, Func func) where T : class, ITreeChildren
{
return Flatten(items).Where(func);
}
///
/// 过滤
///
///
///
///
///
public static IEnumerable> Filter(this IEnumerable> items, Func, bool> func) where T : class
{
return Flatten(items).Where(func);
}
///
/// 过滤
///
///
///
///
///
public static IEnumerable Filter(this T item, Func func) where T : class, ITreeChildren
{
return Flatten(item).Where(func);
}
///
/// 过滤
///
///
///
///
///
public static IEnumerable> Filter(this Tree item, Func, bool> func) where T : class
{
return Flatten(item).Where(func);
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable Flatten(this IEnumerable items, Action optionAction = null) where T : class, ITreeChildren
{
if (items == null)
{
yield break;
}
// 使用一个栈来存储待处理的节点
var stack = new Stack();
// 首先将所有项压入栈中
foreach (var item in items)
{
stack.Push(item);
}
// 循环直到栈为空
while (stack.Count > 0)
{
// 弹出栈顶的节点
var currentItem = stack.Pop();
yield return currentItem;
// 为当前节点设置子节点,如果optionAction不为空,则对每个子节点执行操作
var children = currentItem.Children ?? new List();
foreach (var child in children)
{
optionAction?.Invoke(child, currentItem);
stack.Push(child); // 将子节点压入栈中
}
}
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable Flatten(this T p, Action optionAction = null) where T : class, ITreeChildren
{
if (p == null)
{
return [];
}
return Flatten([p], t => t.Children, optionAction);
}
///
/// 平铺开任意树形结构数据
///
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable Flatten(this IEnumerable items, Func> selector, Action optionAction = null)
{
if (items == null)
{
yield break;
}
// 使用一个队列来存储待处理的节点
var queue = new Queue();
// 首先将所有项加入队列
foreach (var item in items)
{
queue.Enqueue(item);
}
// 循环直到队列为空
while (queue.Count > 0)
{
// 从队列中取出当前节点
var currentItem = queue.Dequeue();
// 将当前节点返回
yield return currentItem;
// 获取当前节点的所有子节点
var children = selector(currentItem) ?? new List();
// 将所有子节点加入队列
foreach (var child in children)
{
// 执行平铺时的操作(如果有的话)
optionAction?.Invoke(child, currentItem);
queue.Enqueue(child);
}
}
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable> Flatten(this IEnumerable> items, Action, Tree> optionAction = null) where T : class
{
if (items == null)
{
return [];
}
return Flatten(items, t => t.Children, optionAction);
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable> Flatten(this Tree p, Action, Tree> optionAction = null) where T : class
{
if (p == null)
{
return [];
}
return Flatten([p], t => t.Children, optionAction);
}
///
/// 平铺开任意树形结构数据
///
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable> Flatten(this IEnumerable> items, Func, IEnumerable>> selector, Action, Tree> optionAction = null)
{
if (items == null)
{
yield break;
}
// 使用一个队列来存储待处理的节点
var queue = new Queue>();
// 首先将所有项加入队列
foreach (var item in items)
{
queue.Enqueue(item);
}
// 循环直到队列为空
while (queue.Count > 0)
{
// 从队列中取出当前节点
var currentItem = queue.Dequeue();
// 将当前节点返回
yield return currentItem;
// 获取当前节点的所有子节点
var children = selector(currentItem) ?? new List>();
// 将所有子节点加入队列
foreach (var child in children)
{
// 执行平铺时的操作(如果有的话)
optionAction?.Invoke(child, currentItem);
queue.Enqueue(child);
}
}
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
/// 根对象parentId的值
///
public static List ToTree(this IEnumerable source, Expression> idSelector, Expression> pidSelector, string topValue = default) where T : ITreeParent, ITreeChildren
{
return ToTree(source, idSelector, pidSelector, topValue);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
/// 根对象parentId的值
///
public static List ToTree(this IEnumerable source, Expression> idSelector, Expression> pidSelector, int topValue = 0) where T : ITreeParent, ITreeChildren
{
return ToTree(source, idSelector, pidSelector, topValue);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
/// 根对象parentId的值
///
public static List ToTree(this IEnumerable source, Expression> idSelector, Expression> pidSelector, long topValue = 0) where T : ITreeParent, ITreeChildren
{
return ToTree(source, idSelector, pidSelector, topValue);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
/// 根对象parentId的值
///
public static List ToTree(this IEnumerable source, Expression> idSelector, Expression> pidSelector, Guid topValue = default) where T : ITreeParent, ITreeChildren
{
return ToTree(source, idSelector, pidSelector, topValue);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
///
/// 根对象parentId的值
///
public static List ToTree(this IEnumerable source, Expression> idSelector, Expression> pidSelector, TKey topValue = default) where T : ITreeParent, ITreeChildren where TKey : IComparable
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
if (idSelector.Body.ToString() == pidSelector.Body.ToString())
{
throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
}
var pidFunc = pidSelector.Compile();
var idFunc = idSelector.Compile();
return BuildTree(source.Where(t => t != null), idFunc, pidFunc, topValue).ToList();
}
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable source) where T : class, ITreeEntity
{
return ToTree(source);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
///
public static List ToTree(this IEnumerable source, TKey? topValue = null) where T : class, ITreeEntity where TKey : struct, IComparable
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
var list = source.Where(t => t != null).ToList();
return BuildTree(list, topValue).ToList();
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
///
/// 根对象parentId的值
///
public static List ToTree(this IEnumerable source, Expression> idSelector, Expression> pidSelector, TKey? topValue = default) where T : ITreeChildren where TKey : struct
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
if (idSelector.Body.ToString() == pidSelector.Body.ToString())
{
throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
}
var pidFunc = pidSelector.Compile();
var idFunc = idSelector.Compile();
source = source.Where(t => t != null).ToList();
return BuildTree(source, idFunc, pidFunc, topValue).ToList();
}
private static IEnumerable BuildTree(IEnumerable source, Func idSelector, Func pidSelector, TKey topValue = default) where T : ITreeChildren where TKey : IComparable
{
// 创建一个字典,用于快速查找节点的子节点
var childrenLookup = new Dictionary>();
var list = source as ICollection ?? source.ToList();
foreach (var item in list.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
{
childrenLookup[idSelector(item)] = new List();
}
// 构建树结构
foreach (var item in list.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item))))
{
childrenLookup[pidSelector(item)].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in list.Where(x => Equals(pidSelector(x), topValue)))
{
// 为根节点和所有子节点设置Children属性
// 使用队列来模拟递归过程
var queue = new Queue();
queue.Enqueue(root);
while (queue.Count > 0)
{
// 出队当前节点
var current = queue.Dequeue();
// 为当前节点设置子节点
if (childrenLookup.TryGetValue(idSelector(current), out var children))
{
current.Children = children;
foreach (var child in children)
{
// 如果子节点实现了ITreeParent接口,则设置其Parent属性
if (child is ITreeParent tree)
{
tree.Parent = current;
}
// 将子节点入队以继续处理
queue.Enqueue(child);
}
}
}
yield return root;
}
}
internal static IEnumerable BuildTree(IEnumerable source, TKey? topValue = default) where T : ITreeEntity where TKey : struct, IComparable
{
return BuildTree(source, t => t.Id, t => t.ParentId, topValue);
}
internal static IEnumerable BuildTree(IEnumerable source, string topValue = null) where T : ITreeEntity
{
return BuildTree(source, t => t.Id, t => t.ParentId, topValue);
}
internal static IEnumerable BuildTree(IEnumerable source, T parent) where T : ITreeEntity
{
// 创建一个字典,用于快速查找节点的子节点
var childrenLookup = new NullableDictionary>();
var list = source as ICollection ?? source.ToList();
foreach (var item in list.Where(item => !childrenLookup.ContainsKey(item.Id)))
{
childrenLookup[item.Id] = new List();
}
// 构建树结构
foreach (var item in list.Where(item => !string.IsNullOrEmpty(item.ParentId) && childrenLookup.ContainsKey(item.ParentId)))
{
childrenLookup[item.ParentId].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in list.Where(x => x.Id == parent.Id))
{
// 为根节点和所有子节点设置Children属性
// 使用队列来模拟递归过程
var queue = new Queue();
queue.Enqueue(root);
while (queue.Count > 0)
{
// 出队当前节点
var current = queue.Dequeue();
// 为当前节点设置子节点
if (childrenLookup.TryGetValue(current.Id, out var children))
{
current.Children = children;
foreach (var child in children)
{
// 如果子节点实现了ITreeParent接口,则设置其Parent属性
if (child is ITreeParent tree)
{
tree.Parent = current;
}
// 将子节点入队以继续处理
queue.Enqueue(child);
}
}
}
yield return root;
}
}
private static IEnumerable BuildTree(IEnumerable source, Func idSelector, Func pidSelector, TKey? topValue = default) where T : ITreeChildren where TKey : struct
{
// 创建一个字典,用于快速查找节点的子节点
var childrenLookup = new NullableDictionary>();
var list = source as ICollection ?? source.ToList();
foreach (var item in list.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
{
childrenLookup[idSelector(item)] = new List();
}
// 构建树结构
foreach (var item in list.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item) ?? default)))
{
childrenLookup[pidSelector(item) ?? default].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in list.Where(x => Equals(pidSelector(x), topValue)))
{
// 为根节点和所有子节点设置Children属性
// 使用队列来模拟递归过程
var queue = new Queue();
queue.Enqueue(root);
while (queue.Count > 0)
{
// 出队当前节点
var current = queue.Dequeue();
// 为当前节点设置子节点
if (childrenLookup.TryGetValue(idSelector(current), out var children))
{
current.Children = children;
foreach (var child in children)
{
// 如果子节点实现了ITreeParent接口,则设置其Parent属性
if (child is ITreeParent tree)
{
tree.Parent = current;
}
// 将子节点入队以继续处理
queue.Enqueue(child);
}
}
}
yield return root;
}
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
///
/// 根对象parentId的值
///
public static List> ToTreeGeneral(this IEnumerable source, Expression> idSelector, Expression> pidSelector, TKey topValue = default) where TKey : IComparable
{
if (idSelector.Body.ToString() == pidSelector.Body.ToString())
{
throw new ArgumentException("idSelector和pidSelector不应该为同一字段!");
}
var pidFunc = pidSelector.Compile();
var idFunc = idSelector.Compile();
var list = source.Where(t => t != null).ToList();
return BuildTreeGeneral(list, idFunc, pidFunc, topValue).ToList();
}
private static IEnumerable> BuildTreeGeneral(List list, Func idSelector, Func pidSelector, TKey parent) where TKey : IComparable
{
// 创建一个字典,用于快速查找节点的子节点
var lookup = new Dictionary>>();
foreach (var item in list.Where(item => !lookup.ContainsKey(idSelector(item))))
{
lookup[idSelector(item)] = new List>();
}
// 构建树结构
foreach (var item in list.Where(item => !Equals(pidSelector(item), default(TKey)) && lookup.ContainsKey(pidSelector(item))))
{
lookup[pidSelector(item)].Add(new Tree(item));
}
// 找到根节点,即没有父节点的节点
foreach (var root in list.Where(x => Equals(pidSelector(x), parent)))
{
// 为根节点和所有子节点设置Children属性
var queue = new Queue>();
var item = new Tree(root);
queue.Enqueue(item);
while (queue.Count > 0)
{
// 出队当前节点
var current = queue.Dequeue();
// 为当前节点设置子节点
if (lookup.TryGetValue(idSelector(current.Value), out var children))
{
current.Children = children;
foreach (var child in children)
{
child.Parent = current.Parent;
// 将子节点入队以继续处理
queue.Enqueue(child);
}
}
}
yield return item;
}
}
///
/// 所有子级
///
public static ICollection AllChildren(this T tree) where T : ITreeChildren => GetChildren(tree, c => c.Children);
///
/// 所有子级
///
public static ICollection AllChildren(this T tree, Func> selector) where T : ITreeChildren => GetChildren(tree, selector);
///
/// 所有子级
///
public static ICollection> AllChildren(this Tree tree) => GetChildren(tree, c => c.Children);
///
/// 所有子级
///
public static ICollection> AllChildren(this Tree tree, Func, IEnumerable>> selector) => GetChildren(tree, selector);
///
/// 所有父级
///
public static List AllParent(this T tree) where T : class, ITreeParent => GetParents(tree, c => c.Parent);
///
/// 所有父级
///
public static List AllParent(this T tree, Func selector) where T : class, ITreeParent => GetParents(tree, selector);
///
/// 所有父级
///
public static List> AllParent(this Tree tree, Func, Tree> selector) => GetParents(tree, selector);
///
/// 是否是根节点
///
public static bool IsRoot(this ITreeParent tree) where T : ITreeParent => tree.Parent == null;
///
/// 是否是叶子节点
///
public static bool IsLeaf(this ITreeChildren tree) where T : ITreeChildren => tree.Children?.Count == 0;
///
/// 是否是根节点
///
public static bool IsRoot(this Tree tree) => tree.Parent == null;
///
/// 是否是叶子节点
///
public static bool IsLeaf(this Tree tree) => tree.Children?.Count == 0;
///
/// 深度层级
///
public static int Level(this T tree) where T : class, ITreeParent
{
if (tree == null)
{
throw new ArgumentNullException(nameof(tree), "当前节点不能为null");
}
// 使用一个队列来存储待处理的节点
var queue = new Queue();
queue.Enqueue(tree);
int level = 1;
// 循环直到队列为空
while (queue.Count > 0)
{
int nodeCount = queue.Count; // 当前层级的节点数
for (int i = 0; i < nodeCount; i++)
{
// 从队列中出队一个节点
T currentNode = queue.Dequeue();
// 如果当前节点是根节点,则返回当前层级
if (currentNode.Parent == null)
{
return level;
}
// 将当前节点的父节点入队
if (currentNode.Parent != null)
{
queue.Enqueue(currentNode.Parent);
}
}
// 完成当前层级的遍历,准备进入下一层级
level++;
}
// 如果执行到这里,说明没有找到根节点
throw new InvalidOperationException("未找到根节点");
}
///
/// 节点路径(UNIX路径格式,以“/”分隔)
///
public static string Path(this T tree) where T : class, ITree => GetFullPath(tree, t => t.Name);
///
/// 节点路径(UNIX路径格式,以“/”分隔)
///
public static string Path(this T tree, Func selector) where T : class, ITreeParent => GetFullPath(tree, selector);
///
/// 节点路径
///
///
/// 分隔符
public static string Path(this T tree, string separator) where T : class, ITree => GetFullPath(tree, t => t.Name, separator);
///
/// 节点路径
///
///
///
/// 选择字段
/// 分隔符
///
public static string Path(this T tree, Func selector, string separator) where T : class, ITreeParent => GetFullPath(tree, selector, separator);
///
/// 根节点
///
public static T Root(this T tree) where T : class, ITreeParent => GetRoot(tree, t => t.Parent);
private static string GetFullPath(T c, Func selector, string separator = "/") where T : class, ITreeParent
{
if (c == null || selector == null)
{
throw new ArgumentNullException(c == null ? nameof(c) : nameof(selector), "当前节点或选择器不能为null");
}
// 使用一个栈来存储节点,栈将逆序存储路径中的节点
var stack = new Stack();
var currentNode = c;
while (currentNode != null)
{
stack.Push(currentNode);
currentNode = currentNode.Parent;
}
// 构建路径字符串
return stack.Select(selector).Join(separator);
}
///
/// 根节点
///
public static T GetRoot(T c, Func selector) where T : class, ITreeParent
{
if (c == null || selector == null)
{
throw new ArgumentNullException(c == null ? nameof(c) : nameof(selector), "当前节点或父级选择器不能为null");
}
// 使用一个集合来存储已访问的节点,以避免无限循环
var visited = new HashSet();
T currentNode = c;
// 向上遍历直到找到根节点
while (currentNode != null)
{
// 如果当前节点已被访问,说明存在循环引用,抛出异常
if (!visited.Add(currentNode))
{
throw new InvalidOperationException("节点存在循环引用");
}
var parent = selector(currentNode);
if (parent == null)
{
// 找到了根节点
return currentNode;
}
currentNode = parent;
}
// 如果currentNode为null,说明最初的节点c就是根节点
return c;
}
///
/// 递归取出所有下级
///
///
///
///
private static List GetChildren(T t, Func> selector)
{
if (t == null || selector == null)
{
return new List(); // 如果t或selector为null,则返回空列表
}
var list = new List();
var queue = new Queue();
queue.Enqueue(t);
while (queue.Count > 0)
{
var current = queue.Dequeue();
list.Add(current); // 将当前节点添加到结果列表
var children = selector(current) ?? new List();
foreach (var child in children)
{
// 只有当子节点还有自己的子节点时,才将其加入队列
if (selector(child).Any())
{
queue.Enqueue(child);
}
}
}
return list;
}
///
/// 递归取出所有上级
///
///
///
///
private static List GetParents(T t, Func selector) where T : class
{
if (t == null || selector == null)
{
return new List(); // 如果t或selector为null,则返回空列表
}
var parents = new List();
var current = t;
while (current != null)
{
// 添加当前节点到父节点列表
parents.Add(current);
// 通过selector函数获取当前节点的父节点
current = selector(current);
// 如果selector返回了已经遍历过的节点,则停止遍历以避免无限循环
if (parents.Contains(current))
{
break;
}
}
// 由于是逆序添加的,所以需要反转列表
parents.Reverse();
return parents;
}
}
public static class TreeExtensionLong
{
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable source) where T : class, ITreeEntity
{
return source.ToTree();
}
}
public static class TreeExtensionGuid
{
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable source) where T : class, ITreeEntity
{
return source.ToTree();
}
}
public static class TreeExtensionString
{
///
/// 平行集合转换成树形结构
///
///
///
///
///
public static List ToTree(this IEnumerable source, string topValue) where T : class, ITreeEntity
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
source = source.Where(t => t != null).ToList();
return TreeExtensions.BuildTree(source, topValue).ToList();
}
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable