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
{
foreach (var item in items.Where(i => i != null))
{
item.Children ??= new List();
item.Children = item.Children.Filter(func).ToList();
if (item.Children.Any() || func(item))
{
yield return item;
}
}
}
///
/// 过滤
///
///
///
///
///
public static IEnumerable> Filter(this IEnumerable> items, Func, bool> func) where T : class
{
foreach (var item in items.Where(i => i != null))
{
item.Children ??= new List>();
item.Children = item.Children.Filter(func).ToList();
if (item.Children.Any() || func(item))
{
yield return item;
}
}
}
///
/// 过滤
///
///
///
///
///
public static IEnumerable Filter(this T item, Func func) where T : class, ITreeChildren
{
return new[] { item }.Filter(func);
}
///
/// 过滤
///
///
///
///
///
public static IEnumerable> Filter(this Tree item, Func, bool> func) where T : class
{
return new[] { item }.Filter(func);
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable Flatten(this IEnumerable items, Action optionAction = null) where T : class, ITreeChildren
{
foreach (var item in items)
{
yield return item;
item.Children ??= new List();
item.Children.ForEach(c => optionAction?.Invoke(c, item));
foreach (var children in item.Children.Flatten(optionAction))
{
yield return children;
}
}
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable Flatten(this T p, Action optionAction = null) where T : class, ITreeChildren
{
yield return p;
foreach (var item in p.Children)
{
yield return item;
item.Children ??= new List();
item.Children.ForEach(c => optionAction?.Invoke(c, item));
foreach (var children in item.Children.Flatten())
{
yield return children;
}
}
}
///
/// 平铺开任意树形结构数据
///
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable Flatten(this IEnumerable items, Func> selector, Action optionAction = null)
{
foreach (var item in items)
{
yield return item;
selector(item).ForEach(c => optionAction?.Invoke(c, item));
foreach (var children in selector(item).Flatten(selector))
{
yield return children;
}
}
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable> Flatten(this IEnumerable> items, Action, Tree> optionAction = null) where T : class
{
foreach (var item in items)
{
yield return item;
item.Children ??= new List>();
item.Children.ForEach(c => optionAction?.Invoke(c, item));
foreach (var tree in item.Children.Flatten())
{
yield return tree;
}
}
}
///
/// 平铺开
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable> Flatten(this Tree p, Action, Tree> optionAction = null) where T : class
{
yield return p;
foreach (var item in p.Children)
{
yield return item;
item.Children ??= new List>();
item.Children.ForEach(c => optionAction?.Invoke(c, item));
foreach (var tree in item.Children.Flatten())
{
yield return tree;
}
}
}
///
/// 平铺开任意树形结构数据
///
///
///
///
/// 平铺时子级需要做的操作,参数1:子级对象,参数2:父级对象
///
public static IEnumerable> Flatten(this IEnumerable> items, Func, IEnumerable>> selector, Action, Tree> optionAction = null)
{
foreach (var item in items)
{
yield return item;
item.Children.ForEach(c => optionAction?.Invoke(c, item));
foreach (var tree in selector(item).Flatten(selector))
{
yield return tree;
}
}
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
/// 根对象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 : ITreeEntity
{
return ToTree(source);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
public static List ToTree(this IEnumerable source, TKey? topValue = default) where T : ITreeEntity where TKey : struct, IComparable
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
source = source.Where(t => t != null).ToList();
return BuildTree(source, 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();
}
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>();
foreach (var item in source.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
{
childrenLookup[idSelector(item)] = new List();
}
// 构建树结构
foreach (var item in source.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item))))
{
childrenLookup[pidSelector(item)].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in source.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
{
// 创建一个字典,用于快速查找节点的子节点
var childrenLookup = new NullableDictionary>();
foreach (var item in source.Where(item => !childrenLookup.ContainsKey(item.Id)))
{
childrenLookup[item.Id] = new List();
}
// 构建树结构
foreach (var item in source.Where(item => (item.ParentId != null || !Equals(item.ParentId, default(TKey))) && childrenLookup.ContainsKey(item.ParentId ?? default)))
{
childrenLookup[item.ParentId ?? default].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in source.Where(x => Equals(x.ParentId, topValue)))
{
// 为根节点和所有子节点设置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;
}
}
internal static IEnumerable BuildTree(IEnumerable source, string topValue = null) where T : ITreeEntity
{
// 创建一个字典,用于快速查找节点的子节点
var childrenLookup = new NullableDictionary>();
foreach (var item in source.Where(item => !childrenLookup.ContainsKey(item.Id)))
{
childrenLookup[item.Id] = new List();
}
// 构建树结构
foreach (var item in source.Where(item => !string.IsNullOrEmpty(item.ParentId) && childrenLookup.ContainsKey(item.ParentId)))
{
childrenLookup[item.ParentId].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in source.Where(x => Equals(x.ParentId, topValue)))
{
// 为根节点和所有子节点设置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>();
foreach (var item in source.Where(item => !childrenLookup.ContainsKey(idSelector(item))))
{
childrenLookup[idSelector(item)] = new List();
}
// 构建树结构
foreach (var item in source.Where(item => !Equals(pidSelector(item), default(TKey)) && childrenLookup.ContainsKey(pidSelector(item) ?? default)))
{
childrenLookup[pidSelector(item) ?? default].Add(item);
}
// 找到根节点,即没有父节点的节点
foreach (var root in source.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();
source = source.Where(t => t != null);
var temp = new List>();
foreach (var item in source.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
{
var parent = new Tree(item);
BuildTree(source, parent, idFunc, pidFunc);
temp.Add(parent);
}
return temp;
}
private static void BuildTree(IEnumerable source, Tree parent, Func idSelector, Func pidSelector) where TKey : IComparable
{
var temp = new List>();
foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent.Value)) == true))
{
var p = new Tree(item);
BuildTree(source, p, idSelector, pidSelector);
p.Parent = parent.Value;
temp.Add(p);
}
parent.Children = temp;
}
///
/// 所有子级
///
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 ICollection AllParent(this T tree) where T : ITreeParent => GetParents(tree, c => c.Parent);
///
/// 所有父级
///
public static ICollection AllParent(this T tree, Func selector) where T : ITreeParent => GetParents(tree, selector);
///
/// 所有父级
///
public static ICollection> 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 ITreeParent tree) where T : ITreeParent => IsRoot(tree) ? 1 : Level(tree.Parent) + 1;
///
/// 节点路径(UNIX路径格式,以“/”分隔)
///
public static string Path(this T tree) where T : ITree => GetFullPath(tree, t => t.Name);
///
/// 节点路径(UNIX路径格式,以“/”分隔)
///
public static string Path(this T tree, Func selector) where T : ITreeParent => GetFullPath(tree, selector);
///
/// 节点路径
///
///
/// 分隔符
public static string Path(this T tree, string separator) where T : ITree => GetFullPath(tree, t => t.Name, separator);
///
/// 节点路径
///
///
///
/// 选择字段
/// 分隔符
///
public static string Path(this T tree, Func selector, string separator) where T : ITreeParent => GetFullPath(tree, selector, separator);
///
/// 根节点
///
public static T Root(this T tree) where T : ITreeParent => GetRoot(tree, t => t.Parent);
private static string GetFullPath(T c, Func selector, string separator = "/") where T : ITreeParent => c.Parent != null ? GetFullPath(c.Parent, selector, separator) + separator + selector(c) : selector(c);
///
/// 根节点
///
public static T GetRoot(T c, Func selector) where T : ITreeParent => c.Parent != null ? GetRoot(c.Parent, selector) : c;
///
/// 递归取出所有下级
///
///
///
///
private static List GetChildren(T t, Func> selector)
{
return selector(t).Union(selector(t).Where(c => selector(c)?.Any() == true).SelectMany(c => GetChildren(c, selector))).ToList();
}
///
/// 递归取出所有上级
///
///
///
private static List GetParents(T t, Func selector)
{
var list = new List() { selector(t) };
if (selector(t) != null)
{
return list.Union(GetParents(selector(t), selector)).Where(x => x != null).ToList();
}
list.RemoveAll(x => x == null);
return list;
}
}
public static class TreeExtensionLong
{
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable source) where T : ITreeEntity
{
return source.ToTree();
}
}
public static class TreeExtensionGuid
{
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable source) where T : ITreeEntity
{
return source.ToTree();
}
}
public static class TreeExtensionString
{
///
/// 平行集合转换成树形结构
///
///
///
///
///
public static List ToTree(this IEnumerable source, string topValue = null) where T : ITreeEntity
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
source = source.Where(t => t != null).ToList();
return TreeExtensions.BuildTree(source, topValue).ToList();
}
}
}