使用LINQ渲染层次?
假设我们有一节课使用LINQ渲染层次?,linq,entity-framework,select,hierarchy,Linq,Entity Framework,Select,Hierarchy,假设我们有一节课 Category { ID, Name, ParentID } 和一份清单 1, 'Item 1', 0 2, 'Item 2', 0 3, 'Item 3', 0 4, 'Item 1.1', 1 5, 'Item 3.1', 3 6, 'Item 1.1.1', 4 7, 'Item 2.1', 2 我们是否可以使用LINQ渲染树,如: Item 1 Item 1.1 Item 1.1.1 Item 2 Item 2.1 Item 3 Ite
Category
{
ID,
Name,
ParentID
}
和一份清单
1, 'Item 1', 0
2, 'Item 2', 0
3, 'Item 3', 0
4, 'Item 1.1', 1
5, 'Item 3.1', 3
6, 'Item 1.1.1', 4
7, 'Item 2.1', 2
我们是否可以使用LINQ渲染树,如:
Item 1
Item 1.1
Item 1.1.1
Item 2
Item 2.1
Item 3
Item 3.1
感谢您的帮助 您可以使用递归:
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
public int ParentID { get; set; }
public List<Category> Children { get; set; }
}
class Program
{
static void Main()
{
List<Category> categories = new List<Category>()
{
new Category () { ID = 1, Name = "Item 1", ParentID = 0},
new Category() { ID = 2, Name = "Item 2", ParentID = 0 },
new Category() { ID = 3, Name = "Item 3", ParentID = 0 },
new Category() { ID = 4, Name = "Item 1.1", ParentID = 1 },
new Category() { ID = 5, Name = "Item 3.1", ParentID = 3 },
new Category() { ID = 6, Name = "Item 1.1.1", ParentID = 4 },
new Category() { ID = 7, Name = "Item 2.1", ParentID = 2 }
};
List<Category> hierarchy = new List<Category>();
hierarchy = categories
.Where(c => c.ParentID == 0)
.Select(c => new Category() { ID = c.ID, Name = c.Name, ParentID = c.ParentID, Children = GetChildren(categories, c.ID) })
.ToList();
HieararchyWalk(hierarchy);
Console.ReadLine();
}
public static List<Category> GetChildren(List<Category> categories, int parentId)
{
return categories
.Where(c => c.ParentID == parentId)
.Select(c => new Category { ID = c.ID, Name = c.Name, ParentID = c.ParentID, Children = GetChildren(categories, c.ID) })
.ToList();
}
public static void HieararchyWalk(List<Category> hierarchy)
{
if (hierarchy != null)
{
foreach (var item in hierarchy)
{
Console.WriteLine(string.Format("{0} {1}", item.ID, item.Name));
HieararchyWalk(item.Children);
}
}
}
}
公共类类别
{
公共int ID{get;set;}
公共字符串名称{get;set;}
public int ParentID{get;set;}
公共列表子项{get;set;}
}
班级计划
{
静态void Main()
{
列表类别=新列表()
{
新类别(){ID=1,Name=“Item 1”,ParentID=0},
新类别(){ID=2,Name=“Item 2”,ParentID=0},
新类别(){ID=3,Name=“Item 3”,ParentID=0},
新类别(){ID=4,Name=“Item 1.1”,ParentID=1},
新类别(){ID=5,Name=“Item 3.1”,ParentID=3},
新类别(){ID=6,Name=“Item 1.1.1”,ParentID=4},
新类别(){ID=7,Name=“Item 2.1”,ParentID=2}
};
列表层次结构=新列表();
层次结构=类别
。其中(c=>c.ParentID==0)
.Select(c=>newcategory(){ID=c.ID,Name=c.Name,ParentID=c.ParentID,Children=GetChildren(categories,c.ID)})
.ToList();
等级交叉道(等级);
Console.ReadLine();
}
公共静态列表GetChildren(列表类别,int-parentId)
{
退货类别
.Where(c=>c.ParentID==ParentID)
.Select(c=>newcategory{ID=c.ID,Name=c.Name,ParentID=c.ParentID,Children=GetChildren(categories,c.ID)})
.ToList();
}
公共静态void层次结构(列表层次结构)
{
if(层次结构!=null)
{
foreach(层次结构中的变量项)
{
WriteLine(string.Format(“{0}{1}”,item.ID,item.Name));
层次交叉道(项目.儿童);
}
}
}
}
这些扩展方法正是您想要的:
public static partial class LinqExtensions
{
public class Node<T>
{
internal Node() { }
public int Level { get; internal set; }
public Node<T> Parent { get; internal set; }
public T Item { get; internal set; }
public IList<Node<T>> Children { get; internal set; }
}
public static IEnumerable<Node<T>> ByHierarchy<T>(
this IEnumerable<T> source,
Func<T, bool> startWith,
Func<T, T, bool> connectBy)
{
return source.ByHierarchy<T>(startWith, connectBy, null);
}
private static IEnumerable<Node<T>> ByHierarchy<T>(
this IEnumerable<T> source,
Func<T, bool> startWith,
Func<T, T, bool> connectBy,
Node<T> parent)
{
int level = (parent == null ? 0 : parent.Level + 1);
if (source == null)
throw new ArgumentNullException("source");
if (startWith == null)
throw new ArgumentNullException("startWith");
if (connectBy == null)
throw new ArgumentNullException("connectBy");
foreach (T value in from item in source
where startWith(item)
select item)
{
var children = new List<Node<T>>();
Node<T> newNode = new Node<T>
{
Level = level,
Parent = parent,
Item = value,
Children = children.AsReadOnly()
};
foreach (Node<T> subNode in source.ByHierarchy<T>(possibleSub => connectBy(value, possibleSub),
connectBy, newNode))
{
children.Add(subNode);
}
yield return newNode;
}
}
public static void DumpHierarchy<T>(this IEnumerable<Node<T>> nodes, Func<T, string> display)
{
DumpHierarchy<T>(nodes, display, 0);
}
private static void DumpHierarchy<T>(IEnumerable<LinqExtensions.Node<T>> nodes, Func<T, string> display, int level)
{
foreach (var node in nodes)
{
for (int i = 0; i < level; i++) Console.Write(" ");
Console.WriteLine (display(node.Item));
if (node.Children != null)
DumpHierarchy(node.Children, display, level + 1);
}
}
}
公共静态部分类LinqExtensions
{
公共类节点
{
内部节点(){}
公共整数级别{get;内部集合;}
公共节点父节点{get;内部集;}
公共T项{get;内部集合;}
公共IList子项{get;内部集;}
}
公共静态IEnumerable ByHierarchy(
这是一个数不清的来源,
Func startWith,
Func(连接方式)
{
返回source.ByHierarchy(startWith、connectBy、null);
}
私有静态IEnumerable ByHierarchy(
这是一个数不清的来源,
Func startWith,
Func connectBy,
节点(父节点)
{
int-level=(parent==null?0:parent.level+1);
if(source==null)
抛出新的ArgumentNullException(“源”);
if(startWith==null)
抛出新的ArgumentNullException(“startWith”);
if(connectBy==null)
抛出新的ArgumentNullException(“connectBy”);
foreach(源中的from项中的T值
其中startWith(项目)
选择项目)
{
var children=新列表();
Node newNode=新节点
{
级别=级别,
父=父,
项目=价值,
Children=Children.AsReadOnly()
};
foreach(source.ByHierarchy中的节点子节点(possibleSub=>connectBy(value,possibleSub)),
connectBy,newNode)
{
添加(子节点);
}
产生返回新节点;
}
}
公共静态void DumpHierarchy(此IEnumerable节点,Func显示)
{
转储层次结构(节点,显示,0);
}
私有静态void DumpHierarchy(IEnumerable节点、Func显示、int级别)
{
foreach(节点中的var节点)
{
对于(inti=0;i
您可以按如下方式使用它们:
categories.ByHierarchy(
cat => cat.ParentId == null, // assuming ParentId is Nullable<int>
(parent, child) => parent.Id == child.ParentId)
.DumpHierarchy(cat => cat.Name);
categories.ByHierarchy(
cat=>cat.ParentId==null,//假设ParentId可为null
(父,子)=>parent.Id==child.ParentId)
.DumpHierarchy(cat=>cat.Name);
以下是“仅限LINQ”版本:
public IEnumerable GetHelpPageMenuItems()
{
var helpPages=(从Context.helpPages中的h选择新的HelpPageMenuItem{HelpPageId=h.HelpPageId,ParentHelpPageId=h.ParentHelpPageId,PageContext=h.PageContext,MenuText=h.MenuText});
var parents=从帮助页面中的h开始,其中!h.ParentHelpPageId.HasValue选择PopulateChildren(h,帮助页面);
返回parents.ToList();
}
私有静态HelpPageMenuItem PopulateChildren(HelpPageMenuItem HelpPageMenuItem,IEnumerable helpPages)
{
helpPageMenuItem.ChildHelpPages=
(从帮助页中的h开始)
其中h.ParentHelpPageId==helpPageMenuItem.HelpPageId
选择PopulateChildren(h,helpPages)).ToList();
返回helpPageMenuItem;
}
@型号列表
@{
Func recuresive=null;
recuresive=(parentid,list)=>string.Join(“,list.Where(x=>x.parentid==parentid)。选择(x=>”“+x.Name+”“+recuresive(x.Id,list.Where(y=>y.parentid!=parentid.)+”
>);
}
@Html.Raw(“”+递归(null,Model)+“”)
公共静态列表BuildTreeView(此列表包含所有项)
,Func parentSelector,Func childSelector,Expression ChildrenProperty选择器
,Func GetRoot,List rootList=null)
{
if(rootList==null)
根列表
Func<int, int, string[]> build = null;
build = (p, n) =>
{
return (from x in categories
where x.ParentID == p
from y in new[]
{
"".PadLeft(n)+ x.Name
}.Union(build(x.ID, n + 1))
select y).ToArray();
};
var lines = build(0, 0);
Func<IEnumerable<int>, int, string[]> build = null;
build = (ps, n) =>
{
return (from x in categories
where ps.Contains(x.ParentID)
from y in new[]
{
"".PadLeft(n)+ x.Name
}.Union(build(new [] { x.ID }, n + 1))
select y).ToArray();
};
var roots = (from c in categories
join p in categories on c.ParentID equals p.ID into gps
where !gps.Any()
orderby c.ParentID
select c.ParentID).Distinct();
var lines = build(roots, 0);
public IEnumerable<HelpPageMenuItem> GetHelpPageMenuItems()
{
var helpPages = (from h in Context.HelpPages select new HelpPageMenuItem{HelpPageId = h.HelpPageId, ParentHelpPageId = h.ParentHelpPageId, PageContext = h.PageContext, MenuText = h.MenuText}).ToList();
var parents = from h in helpPages where !h.ParentHelpPageId.HasValue select PopulateChildren(h, helpPages);
return parents.ToList();
}
private static HelpPageMenuItem PopulateChildren(HelpPageMenuItem helpPageMenuItem, IEnumerable<HelpPageMenuItem> helpPages)
{
helpPageMenuItem.ChildHelpPages =
(from h in helpPages
where h.ParentHelpPageId == helpPageMenuItem.HelpPageId
select PopulateChildren(h, helpPages)).ToList();
return helpPageMenuItem;
}
@model List<OrgChart.Models.Node>
@{
Func<int?, List<OrgChart.Models.Node>, string> recuresive = null;
recuresive = (parentid, list) => string.Join("", list.Where(x => x.ParentId == parentid).Select(x => "<li>" + x.Name + "<ul>" + recuresive(x.Id, list.Where(y => y.ParentId != parentid).ToList()) + "</ul></li>"));
}
@Html.Raw("<ul id='org1' >" + recuresive(null, Model) + "</ul>")
<div id="chart" class="orgChart"></div>
public static List<TSource> BuildTreeView<TSource, TKey>(this List<TSource> allItems
, Func<TSource, TKey> parentSelector, Func<TSource, TKey> childSelector, Expression<Func<TSource, List<TSource>>> childrenPropertySelector
, Func<TSource, bool> GetRoot, List<TSource> rootList = null)
{
if (rootList == null)
rootList = allItems.Where(GetRoot).ToList();
if (rootList != null && rootList.Count > 0)
{
rootList.ForEach(rootItem =>
{
Func<TSource, bool> whereClause = x => childSelector(rootItem).Equals(parentSelector(x));
var childrenProperty = (childrenPropertySelector.Body as MemberExpression).Member as System.Reflection.PropertyInfo;
var childrenList = allItems.Where(whereClause).ToList();
childrenProperty.SetValue(rootItem, childrenList);
if (childrenList.Count > 0)
BuildTreeView(allItems, parentSelector, childSelector, childrenPropertySelector, GetRoot, childrenProperty.GetValue(rootItem) as List<TSource>);
});
}
return rootList;
}
List<Channel> rootChannel = listChannel.BuildTreeView(f => f.PARENT_CODE, x => x.CODE, z => z.SubChannels, c => c.CODE == "AC");