C# 在linq中创建一个树结构,其中有一个列表源,其父-子作为对象的字符串
我首先列出一个包含以下数据的列表:C# 在linq中创建一个树结构,其中有一个列表源,其父-子作为对象的字符串,c#,linq,razor,2sxc,C#,Linq,Razor,2sxc,我首先列出一个包含以下数据的列表: Name______________ Parent__________Description_______________FilesCoded________CodingReferences "Blue"____________ "1.Colors"______"whatever"________________10________________11 "Red"_______
Name______________ Parent__________Description_______________FilesCoded________CodingReferences
"Blue"____________ "1.Colors"______"whatever"________________10________________11
"Red"_____________ "1.Colors"______"this"____________________2_________________3
"LightBlue"_______ "Blue"__________"that"____________________3_________________4
"Square"__________ "3.Forms"_______""________________________3_________________6
"ClearBlue"_______ "LightBlue"_____""________________________0_________________0
我需要创建以下输出:
1.Colors
____Blue
________LightBlue
____________ClearBlue
3.Forms
____Square
我使用了这段代码,这很有技巧,但是我在树上有大约15到20个级别,这使得代码很难看而且效率很低。有没有办法做到这一点:
@{
var Cats = AsList(App.Data["Categories"]).OrderBy(o => o.Parent).ThenBy(oo => oo.Name);
// List of objects with: Name, Parent, Description, and other fields.
var FirstLevelTree = Cats.Where(a => Char.IsNumber(a.Name[0])).Select(s => s.Name).Distinct();
}
@functions{
public CategoryInfo setCatInfo (string catName)
{
var Cats = AsList(App.Data["Categories"]);
var returnInfo = new CategoryInfo();
returnInfo.desc = "Error: empty string";
returnInfo.info = "Error: empty string";
var checkCat = Cats.Where(n => n.Name == catName);
if (checkCat.Count() != 1)
{
returnInfo.info = "Error: no such cat in list";
returnInfo.desc = "Error: no such cat in list";
} else {
var thisCat = checkCat.First();
returnInfo.info = thisCat.Name + "somethingelse";
returnInfo.desc = thisCat.Description + "alsosomethingelse";
}
return returnInfo;
}
public class CategoryInfo {
public string info {get;set;}
public string desc {get;set;}
}
}
<div id="myCats">
@foreach(var top in FirstLevelTree)
{
<p>@top</p>
var setlvlOne = Cats.Where(a => a.Parent == top);
foreach(var lvlOne in setlvlOne)
{
var getLvlOneInfo = setCatInfo(lvlOne.Name);
<p style="margin-left: 20px;">@Html.Raw(getLvlOneInfo.info)</p>
if (!String.IsNullOrEmpty(getLvlOneInfo.desc))
{
<p style="margin-left: 30px;">@Html.Raw(getLvlOneInfo.desc)</p>
}
var setlvlTwo = Cats.Where(b => b.Parent == lvlOne.Name);
foreach(var lvlTwo in setlvlTwo)
{
var getLvlTwoInfo = setCatInfo(lvlTwo.Name);
<p style="margin-left: 40px;">@Html.Raw(getLvlTwoInfo.info)</p>
if (!String.IsNullOrEmpty(getLvlTwoInfo.desc))
{
<p style="margin-left: 50px;">@Html.Raw(getLvlTwoInfo.desc)</p>
}
var setlvlThree = Cats.Where(c => c.Parent == lvlTwo.Name);
foreach(var lvlThree in setlvlThree)
{
var getLvlThreeInfo = setCatInfo(lvlThree.Name);
<p style="margin-left: 60px;">@Html.Raw(getLvlThreeInfo.info)</p>
if (!String.IsNullOrEmpty(getLvlThreeInfo.desc))
{
<p style="margin-left: 70px;">@Html.Raw(getLvlThreeInfo.desc)</p>
}
var setlvlFour = Cats.Where(d => d.Parent == lvlThree.Name);
foreach(var lvlFour in setlvlFour)
{
var getLvlFourInfo = setCatInfo(lvlFour.Name);
<p style="margin-left: 80px;">@Html.Raw(getLvlFourInfo.info)</p>
if (!String.IsNullOrEmpty(getLvlFourInfo.desc))
{
<p style="margin-left: 90px;">@Html.Raw(getLvlFourInfo.desc)</p>
}
var setlvlFive = Cats.Where(e => e.Parent == lvlFour.Name);
foreach(var lvlFive in setlvlFive)
{
var getLvlFiveInfo = setCatInfo(lvlFive.Name);
<p style="margin-left: 100px;">@Html.Raw(getLvlFiveInfo.info)</p>
if (!String.IsNullOrEmpty(getLvlFiveInfo.desc))
{
<p style="margin-left: 110px;">@Html.Raw(getLvlFiveInfo.desc)</p>
}
}
}
}
}
}
}
</div>
@{
var Cats=AsList(App.Data[“Categories”]).OrderBy(o=>o.Parent)。ThenBy(oo=>oo.Name);
//具有以下字段的对象列表:名称、父项、说明和其他字段。
var FirstLevelTree=Cats.Where(a=>Char.IsNumber(a.Name[0])).Select(s=>s.Name.Distinct();
}
@功能{
公共类别信息setCatInfo(字符串catName)
{
var Cats=AsList(应用程序数据[“类别]);
var returnInfo=new CategoryInfo();
returnInfo.desc=“错误:空字符串”;
returnInfo.info=“错误:空字符串”;
var checkCat=Cats.Where(n=>n.Name==catName);
如果(检查cat.Count()!=1)
{
returnInfo.info=“错误:列表中没有此类cat”;
returnInfo.desc=“错误:列表中没有此类cat”;
}否则{
var thisCat=checkCat.First();
returnInfo.info=thisCat.Name+“somethingelse”;
returnInfo.desc=thisCat.Description+“alsosomethingelse”;
}
返回返回信息;
}
公共类类别信息{
公共字符串信息{get;set;}
公共字符串desc{get;set;}
}
}
@foreach(FirstLevelTree中的变量top)
{
@顶
var setlvlOne=Cats.Where(a=>a.Parent==top);
foreach(setlvlOne中的变量lvlOne)
{
var getLvlOneInfo=setCatInfo(lvlOne.Name);
@Html.Raw(getLvlOneInfo.info)
如果(!String.IsNullOrEmpty(getLvlOneInfo.desc))
{
@Html.Raw(getLvlOneInfo.desc)
}
var setlvlTwo=Cats.Where(b=>b.Parent==lvlOne.Name);
foreach(setlvlTwo中的var lvlTwo)
{
var getLvlTwoInfo=setCatInfo(lvlTwo.Name);
@Html.Raw(getLvlTwoInfo.info)
如果(!String.IsNullOrEmpty(getLvlTwoInfo.desc))
{
@Html.Raw(getLvlTwoInfo.desc)
}
var setlvltree=Cats.Where(c=>c.Parent==lvlTwo.Name);
foreach(setlvltree中的var lvltree)
{
var getLvlThreeInfo=setCatInfo(lvlThree.Name);
@Html.Raw(getLvlThreeInfo.info)
如果(!String.IsNullOrEmpty(getLvlThreeInfo.desc))
{
@Html.Raw(getLvlThreeInfo.desc)
}
var setlvlFour=Cats.Where(d=>d.Parent==lvltree.Name);
foreach(在setlvlFour中的var lvlFour)
{
var getLvlFourInfo=setCatInfo(lvlFour.Name);
@Html.Raw(getLvlFourInfo.info)
如果(!String.IsNullOrEmpty(getLvlFourInfo.desc))
{
@Html.Raw(getLvlFourInfo.desc)
}
var setlvlFive=Cats.Where(e=>e.Parent==lvlFour.Name);
foreach(setlvlFive中的var lvlFive)
{
var getLvlFiveInfo=setCatInfo(lvlFive.Name);
@Html.Raw(getLvlFiveInfo.info)
如果(!String.IsNullOrEmpty(getLvlFiveInfo.desc))
{
@Html.Raw(getLvlFiveInfo.desc)
}
}
}
}
}
}
}
简单的
对。创建一个递归调用自身的。这将允许您避免示例中的所有重复代码,并且它将支持基本上无限的最大深度,而不需要任何更多的代码更改
更快
这取决于你一直在做什么
随着级别的增加,您可能只是生成了更多的HTML。这将在服务器端花费更多的时间,同时也会使浏览器陷入困境。为了避免这种问题,您可能只需要查看加载用户实际感兴趣的部分。例如,您可以创建一个折叠结构,当用户向下钻取数据时,该结构只能从更深的节点加载数据
我还将密切关注您未提供的代码中可能发生的情况
是一项昂贵的操作吗setCatInfo
- 什么是支持猫的集合?如果它使用延迟执行,比如实体框架DbSet,那么每次迭代
调用的结果时,您可能会执行单独的往返Cats.Where(…)
Cats.Where()
都会给页面生成带来O(n²)
算法复杂性。我建议将所有类别收集到一个查找中,按其父类别分组:
var catsByParent = Cats.ToLookup(c => c.Parent);
这是一个一次性的O(logn)
操作,从那以后,您应该能够更快地获得具有给定父级的类别
var thisLevel = catsByParent[parentLevel.Name];
旁注
- 使用
@Html.Raw()。莫斯
@inherits ToSic.Sxc.Dnn.RazorComponent @{ var Cats = AsList(App.Data["Categories"]).OrderBy(o => o.Parent).ThenBy(oo => oo.Name); // List of objects with: Parent, Name, Description, FilesCoded, CodingReferences var CatsGrouped = Cats.ToLookup(a => a.Parent); var FirstLevelTree = Cats.Where(a => Char.IsNumber(a.Name[0])).Select(s => s.Name).Distinct(); } <style> .setmargins{ padding-left: 2em; } </style> @helper getChildren(string CatName, dynamic CatsGrouped) { var setChilds = CatsGrouped[CatName]; <div class="setmargins"> @foreach(var child in setChilds) { <div class="toogle"> @child.Name (a: @child.FilesCoded urs: @child.CodingReferences) <div class="toogletarget setmargins">@(new HtmlString(child.Description))</div> </div> @getChildren(child.Name, CatsGrouped) } </div> } <div id="myCats" @Edit.TagToolbar(Content)> @foreach(var top in FirstLevelTree) { <div>@top</div> @getChildren(top, CatsGrouped) } </div> <script> $( ".toogletarget" ).toggle(); $( ".toogle" ).click(function() { $(this).find('.toogletarget').toggle(); }); </script>