using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Masuit.Tools.Reflection;
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();
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)))
{
item.Parent = default;
TransData(source, item, idFunc, pidFunc);
temp.Add(item);
}
return temp;
}
///
/// 平行集合转换成树形结构
///
///
///
///
public static List ToTree(this IEnumerable source) where T : ITreeEntity
{
return ToTree(source);
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
public static List ToTree(this IEnumerable source) where T : ITreeEntity where TKey : struct, IComparable
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
source = source.Where(t => t != null);
var temp = new List();
foreach (var item in source.Where(item => item.ParentId is null || item.ParentId.Equals(default)))
{
TransData(source, item);
temp.Add(item);
}
return temp;
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
///
/// 根对象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);
var temp = new List();
foreach (var item in source.Where(item => pidFunc(item) is null || pidFunc(item).Equals(topValue)))
{
TransData(source, item, idFunc, pidFunc);
temp.Add(item);
}
return temp;
}
private static void TransData(IEnumerable source, T parent, Func idSelector, Func pidSelector) where T : ITreeChildren where TKey : IComparable
{
var temp = new List();
foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent)) == true))
{
TransData(source, item, idSelector, pidSelector);
if (item is ITreeParent c)
{
c.Parent = parent;
}
temp.Add(item);
}
parent.Children = temp;
}
internal static void TransData(IEnumerable source, T parent) where T : ITreeEntity where TKey : struct, IComparable
{
var temp = new List();
foreach (var item in source.Where(item => item.ParentId?.Equals(parent.Id) == true))
{
TransData(source, item);
if (item is ITreeParent c)
{
c.Parent = parent;
}
temp.Add(item);
}
parent.Children = temp;
}
internal static void TransData(IEnumerable source, T parent) where T : ITreeEntity
{
var temp = new List();
foreach (var item in source.Where(item => item.ParentId?.Equals(parent.Id) == true))
{
TransData(source, item);
if (item is ITreeParent c)
{
c.Parent = parent;
}
temp.Add(item);
}
parent.Children = temp;
}
private static void TransData(IEnumerable source, T parent, Func idSelector, Func pidSelector) where T : ITreeChildren where TKey : struct
{
var temp = new List();
foreach (var item in source.Where(item => pidSelector(item)?.Equals(idSelector(parent)) == true))
{
TransData(source, item, idSelector, pidSelector);
if (item is ITreeParent c)
{
c.Parent = parent;
}
temp.Add(item);
}
parent.Children = temp;
}
///
/// 平行集合转换成树形结构
///
///
///
///
///
///
/// 根对象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);
TransData(source, parent, idFunc, pidFunc);
temp.Add(parent);
}
return temp;
}
private static void TransData(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);
TransData(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) where T : ITreeEntity
{
if (source is IQueryable queryable)
{
source = queryable.ToList();
}
source = source.Where(t => t != null);
var temp = new List();
foreach (var item in source.Where(item => item.ParentId is null || item.ParentId.Equals(default)))
{
TreeExtensions.TransData(source, item);
temp.Add(item);
}
return temp;
}
}
}