LINQ基于childorder对单个列表进行排序
我目前正在尝试找出一种使用LINQ和C#对元素进行排序的好方法,但我有点没有这样做。
对于这个问题,我们假设您有以下表格
---TempTable ID (int) ParentID (int) Name (varchar) SortOrder (int)
ID和ParentID彼此相关,并为我提供了一个自我分层的数据结构。 根元素在ID字段中为空。 SortOrder只是整个表的一部分,并且基于ParentID,因此共享相同ParentID的元素在其中具有1,2,3。
让我们进一步假设以下数据:
ID = 1 ParentID = null Name = Test 1 SortOrder = 1 ID = 2 ParentID = 1 Name = Test 2 SortOrder = 1 ID = 3 ParentID = 1 Name = Test 3 SortOrder = 2 ID = 4 ParentID = 2 Name = Test 4 SortOrder = 1
我想要的平面列表应该具有以下顺序:
Test 1 //root element with sort order 1 = very top Test 2 //child element of root with sort order 1 Test 4 //child element of test 2 with sort order 1 Test 3 //child element of root with sort order 2
此外,我喜欢获取对象本身,而不仅仅获取一部分信息投入使用select new …
这是我失败的尝试之一:
from x in EntityModel.TempTables //DbSet by EntityFramework - which already holds all elements orderby x.SortOrder from y in x.TempTableChildren //Navigation Property by EntityFramework orderby y.SortOrder select y
在此先感谢您的帮助。
编辑:
具有ParentID的订单可能是有用的,对于给定的TestData,因为ID,ParentID处于完美的顺序但是在真实的实时应用程序中不是这样的,因为它的数据驱动,有人可以删除条目创建一个新条目并将其放入在父母之下的某些顺序,你会有类似的东西:
ID = 193475037 ParentID = 2 Name = Test 192375937 SortOrder = 25
现在在应用程序中可以移动这个,ParentID和SortOrder会随机变化为:
ID = 193475037 ParentID = 456798424 Name = Test 192375937 SortOrder = 4
为了解释这里的问题是一些代码 – 如果没有1个漂亮的Linq查询我会怎么做但是有2个和一些收益率返回:
public class LinqTestDemo { Random rand = new Random(); List list = new List(); public List GetFlatData() { list = GetTestData(); var rootElement = (from x in list where x.ParentID == null orderby x.SortOrder select x).ToList(); var flatList = OrderChilds(rootElement).ToList(); foreach (var tempTable in flatList) { Console.WriteLine(string.Format("ID = {0} - ParentID = {1} - Name = {2} - SortOrder = {3}", tempTable.ID, tempTable.ParentID, tempTable.Name, tempTable.SortOrder)); } return flatList; } private IEnumerable OrderChilds(List enumerable) { foreach (var tempTable in enumerable) { yield return tempTable; TempTable table = tempTable; var childs = OrderChilds((from x in list where x.ParentID == table.ID orderby x.SortOrder select x).ToList()); foreach (var child in childs) { yield return child; } } } public List GetTestData() { var returnValue = new List(); for (int i = 0; i < 50; i++) { var tempTable = new TempTable(); tempTable.ID = i; if (i == 0) tempTable.ParentID = null; else tempTable.ParentID = rand.Next(0, i); var maxSortOrder = (from x in returnValue where x.ParentID == tempTable.ParentID select (int?)x.SortOrder).Max(); if (maxSortOrder.HasValue) tempTable.SortOrder = maxSortOrder.Value + 1; else tempTable.SortOrder = 1; tempTable.Name = string.Format("Test {0:00}", i); returnValue.Add(tempTable); } return returnValue; } public class TempTable { public int ID { get; set; } public int? ParentID { get; set; } public string Name { get; set; } public int SortOrder { get; set; } } }
@Browth-First vs Depth-First Traversal:经过一些阅读后,我会说我想要的结果将是Depth-First Traversal,其中同一级别深度的元素应该由属性SortOrder排序。
public lEnumerable GetList( int? parentID = null){ foreach ( var item in Context.TempTables .Where( x => x.ParentID == parentID ) .OrderBy( x=> x.SortOrder) .ToList() { yield return item; foreach( var child in GetList( item.ID)) { yield return child; } } } var sortedList = GetList();
它类似于您的方法,但它更小和递归。 适用于许多深度级别。 我更喜欢调用ToList,因为它会在查询下一个查询之前关闭结果集。
到目前为止,在单个查询中无法执行此操作。
请求单个查询
entity framework将自动填充所有孩子。
public IEnumerable PrepareList(IEnumerable list){ list = list.OrderBy( x=> x.SortOrder); foreach(var item in list){ yield return item; foreach(var child in PrepareList(item.ChildTempTables)){ yield return child; } } } // since EF will automatically fill each children on fetch // all we need is just a top level nodes // which we will pass to PrepareList method var list = Context.TempTables.ToList().Where(x=> x.ParentID == null); var sortedList = PrepareList(list).ToList(); // it is good to create list at the end if you are going to // iterate it many times and logic will not change.
这是一个非递归版本。 它不会在初始列表中一次又一次地迭代。 相反,它维护父子关系的字典,并将正在进行的预订树遍历的当前位置存储在枚举器中。
public static IEnumerable PreorderForest(IEnumerable list) { var nodesByParent = list.GroupBy(x => x.ParentID.GetValueOrDefault(-1)) .ToDictionary(xs => xs.Key, xs => xs.OrderBy(x => x.SortOrder).GetEnumerator()); var stack = new Stack>(); stack.Push(nodesByParent[-1]); while (stack.Count > 0) { var nodes = stack.Peek(); if (nodes.MoveNext()) { yield return nodes.Current; IEnumerator children; if (nodesByParent.TryGetValue(nodes.Current.ID, out children)) stack.Push(children); } else stack.Pop(); } }
实际上我不知道它是否可以通过优雅的LINQ查询。 这是DFS的递归版本,它构建查找以加快ParentID
搜索速度
public static IEnumerable SortedList(IEnumerable list = null, int? ParentID = null, ILookup lookup = null) { if (lookup == null) lookup = list.ToLookup(x => x.ParentID, x => x); foreach (var p in lookup[ParentID].OrderBy(x => x.SortOrder)) { yield return p; foreach (var c in SortedList(lookup: lookup, ParentID: p.ID)) yield return c; } }
试试这个:
public class Item { public int ID { get; set; } public int? ParentID { get; set; } public string Name { get; set; } public int SortOrder { get; set; } } public void DoWork() { Item[] data = new Item[] { new Item() { ID = 2, ParentID = 1, Name = "Test 2", SortOrder = 1}, new Item() { ID = 3, ParentID = 1, Name = "Test 3", SortOrder = 2}, new Item() { ID = 4, ParentID = 2, Name = "Test 4", SortOrder = 1}, new Item() { ID = 1, ParentID = null, Name = "Test 1", SortOrder = 1}, }; var result = from x in data orderby x.SortOrder, x.ParentID select x; foreach (var row in result.ToArray()) { Console.WriteLine(row.Name); } }
我想这都是正确的订购
这是一个简单的解决方案:
public class TempTable { public int ID {get;set;} public int? ParentID {get;set;} public String Name {get;set;} public int SortOrder {get;set;} } public List GetTempData() { var temp = new List (); temp.Add(new TempTable { ID = 1, ParentID = null, Name = "Test 1", SortOrder = 1 }); temp.Add(new TempTable { ID = 2, ParentID = 1, Name = "Test 2", SortOrder = 1 }); temp.Add(new TempTable { ID = 3, ParentID = 1, Name = "Test 3", SortOrder = 3 }); temp.Add(new TempTable { ID = 4, ParentID = 2, Name = "Test 4", SortOrder = 1 }); temp.Add(new TempTable { ID = 5, ParentID = 1, Name = "Test 5", SortOrder = 2 }); return temp; }
用法:
上述就是C#学习教程:LINQ基于childorder对单个列表进行排序分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
var data = GetTempData(); var result = data.OrderBy(d => d.SortOrder).ThenBy(d => d.ParentID); //Do something with result
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/988208.html