// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
///
/// 树扩展方法
///
public static class TreeExtensions
{
///
/// 转为树形结构
///
/// 树节点数据类型
/// 源数据集合
/// 判断父子关系的函数,第一个参数为父级,第二个参数为子级
/// 转换后的树形结构根节点集合
public static IEnumerable> ToTree(this IEnumerable source, Func isChild)
{
var nodes = source.Select(value => new TreeNode(value)).ToList();
var visited = new HashSet();
foreach (var node in nodes)
{
if (visited.Contains(node.Value))
{
continue;
}
var stack = new Stack>();
stack.Push(node);
while (stack.Count > 0)
{
var current = stack.Pop();
if (visited.Contains(current.Value))
{
throw new InvalidOperationException("转为树形结构时,循环依赖检测到");
}
_ = visited.Add(current.Value);
foreach (var child in nodes.Where(child => isChild(current.Value, child.Value)))
{
current.Children.Add(child);
stack.Push(child);
}
}
}
return nodes.Where(node => !nodes.Any(n => n.Children.Contains(node)));
}
///
/// 根据主键和父级主键生成树形结构
///
/// 树节点数据类型
/// 源数据集合
/// 主键选择器
/// 父级主键选择器
/// 树形结构
public static IEnumerable> ToTree(this IEnumerable source, Func keySelector, Func parentKeySelector)
{
var nodes = source.Select(value => new TreeNode(value)).ToList();
var lookup = nodes.ToLookup(node => parentKeySelector(node.Value), node => node);
foreach (var node in nodes)
{
node.Children.AddRange(lookup[keySelector(node.Value)]);
}
return nodes.Where(node => !nodes.Any(n => keySelector(n.Value).Equals(parentKeySelector(node.Value))));
}
///
/// 添加子节点
///
/// 树节点数据类型
/// 父节点
/// 要添加的子节点值
///
public static void AddChild(this TreeNode parent, T value)
{
ArgumentNullException.ThrowIfNull(parent);
parent.Children.Add(new TreeNode(value));
}
///
/// 添加子节点到指定的父节点
///
/// 树节点数据类型
/// 源数据集合
/// 父节点对象
/// 子节点对象
/// 主键选择器
/// 父级主键选择器
public static void AddChild(this IEnumerable> source, T parent, T child, Func keySelector, Func parentKeySelector)
{
if (parent is null)
{
throw new ArgumentNullException(nameof(parent), "父节点不能为空");
}
if (child is null)
{
throw new ArgumentNullException(nameof(child), "子节点不能为空");
}
var parentNode = source
.DepthFirstTraversal()
.FirstOrDefault(node => keySelector(node.Value).Equals(keySelector(parent)))
?? throw new InvalidOperationException("在树中未找到父节点");
_ = parentKeySelector.Invoke(child).SetPropertyValue("Children", keySelector(parent));
parentNode.Children.Add(new TreeNode(child));
}
///
/// 删除节点
///
/// 树节点数据类型
/// 根节点
/// 要删除的节点值
/// 如果成功删除节点则返回 true,否则返回 false
public static bool RemoveNode(this TreeNode? root, T value)
{
if (root is null)
{
return false;
}
foreach (var child in root.Children.ToList())
{
if (EqualityComparer.Default.Equals(child.Value, value))
{
_ = root.Children.Remove(child);
return true;
}
if (RemoveNode(child, value))
{
return true;
}
}
return false;
}
///
/// 深度优先遍历 (DFS)
///
/// 树节点数据类型
/// 根节点
/// 深度优先遍历的节点序列
public static IEnumerable> DepthFirstTraversal(this TreeNode? root)
{
if (root is null)
{
yield break;
}
yield return root;
foreach (var child in root.Children)
{
foreach (var descendant in child.DepthFirstTraversal())
{
yield return descendant;
}
}
}
///
/// 深度优先遍历 (DFS) - 遍历树形结构中所有节点
///
/// 树节点数据类型
/// 树形结构根节点集合
/// 深度优先遍历的节点序列
public static IEnumerable> DepthFirstTraversal(this IEnumerable>? source)
{
if (source is null)
{
yield break;
}
foreach (var root in source)
{
foreach (var node in root.DepthFirstTraversal())
{
yield return node;
}
}
}
///
/// 广度优先遍历 (BFS)
///
/// 树节点数据类型
/// 根节点
/// 广度优先遍历的节点序列
public static IEnumerable> BreadthFirstTraversal(this TreeNode? root)
{
if (root is null)
{
yield break;
}
var queue = new Queue>();
queue.Enqueue(root);
while (queue.Count > 0)
{
var current = queue.Dequeue();
yield return current;
foreach (var child in current.Children)
{
queue.Enqueue(child);
}
}
}
///
/// 查找节点 (DFS)
///
/// 树节点数据类型
/// 根节点
/// 要查找的节点值
/// 找到的节点,如果未找到则返回 null
public static TreeNode? FindNode(this TreeNode root, T value)
{
return root.DepthFirstTraversal().FirstOrDefault(node => EqualityComparer.Default.Equals(node.Value, value));
}
///
/// 获取节点路径
///
/// 树节点数据类型
/// 根节点
/// 要获取路径的节点值
/// 从根节点到目标节点的路径,如果未找到则返回 null
public static List>? GetPath(this TreeNode root, T value)
{
var path = new List>();
return FindPath(root, value, path) ? path : null;
}
///
/// 获取树的高度
///
/// 树节点数据类型
/// 根节点
/// 树的高度,空树返回 0
public static int GetHeight(this TreeNode? root)
{
return root is null ? 0 : 1 + root.Children.Select(child => child.GetHeight()).DefaultIfEmpty(0).Max();
}
///
/// 获取叶子节点
///
/// 树节点数据类型
/// 根节点
/// 所有叶子节点的集合
public static IEnumerable> GetLeafNodes(this TreeNode root)
{
return root.DepthFirstTraversal().Where(node => node.Children.Count == 0);
}
#region 私有方法
///
/// 查找路径
///
/// 树节点数据类型
/// 当前节点
/// 要查找的节点值
/// 路径记录
/// 如果找到目标节点则返回 true,否则返回 false
private static bool FindPath(TreeNode? node, T value, List> path)
{
if (node is null)
{
return false;
}
path.Add(node);
if (EqualityComparer.Default.Equals(node.Value, value))
{
return true;
}
foreach (var child in node.Children)
{
if (FindPath(child, value, path))
{
return true;
}
}
path.RemoveAt(path.Count - 1);
return false;
}
#endregion 私有方法
///
/// 设置对象属性值
///
///
///
///
///
///
///
public static bool SetPropertyValue(this TEntity entity, string propertyName, TValue value)
{
var objectType = typeof(TEntity);
var propertyInfo = objectType.GetProperty(propertyName);
if (propertyInfo is null || !propertyInfo.PropertyType.IsGenericType)
{
throw new ArgumentException($"属性 '{propertyName}' 不存在,或者不是类型 '{objectType.Name}' 中的泛型类型。");
}
var paramObj = Expression.Parameter(objectType);
var paramVal = Expression.Parameter(typeof(TValue));
var bodyVal = Expression.Convert(paramVal, propertyInfo.PropertyType);
// 获取设置属性的值的方法
var setMethod = propertyInfo.GetSetMethod(true);
// 如果只是只读,则 setMethod==null
if (setMethod is null)
{
return false;
}
var body = Expression.Call(paramObj, setMethod, bodyVal);
var setValue = Expression.Lambda>(body, paramObj, paramVal).Compile();
setValue(entity, value);
return true;
}
}
///
/// 树节点数据传输对象
///
///
public class TreeNode
{
///
/// 构造函数
///
/// 节点值
public TreeNode(T value)
{
Value = value;
}
///
/// 节点值
///
public T Value { get; set; }
///
/// 子节点
///
public List> Children { get; set; } = [];
}