[英]Ordering a self-referencing hierarchy in LINQ
我有一個名為NavigationElement
的類,看起來像這樣
public class NavigationElement
{
public int Id { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public int SortOrder { get; set; }
public bool Visible { get; set; }
public int? ParentId { get; set; }
public virtual ICollection<NavigationElement> Children { get; set; }
public virtual NavigationElement Parent { get; set; }
public NavigationElement()
{
Children = new List<NavigationElement>();
}
}
如您所見,該類是自引用的。 由此,我創建了一個帶有下拉菜單(正在播放層次結構)的站點導航菜單。
我正在努力訂購這些物品。 我希望頂層項目由SortOrder
屬性排序,但是下面的所有內容都希望由Title
屬性按字母順序排序 。
這就是我到目前為止所做的原因。
var orderedModel = unorderedModel.OrderBy(x => x.SortOrder).ThenBy(x => x.Children.OrderBy(y => y.Title).ThenBy(z => z.Children.OrderBy(a => a.Title))).ToList();
unorderedModel
的類型為List<NavigationElementModel>
。
這正在編譯,但是運行代碼時出現錯誤。 錯誤提示:
至少一個對象必須實現IComparable。
您應該只遍歷所有子元素並將其排序。
有點像:
var ordered = unorderedModel.OrderBy(x=>x.SortOrder).ToList();
ordered.ForEach(OrderChildren);
public void OrderChildren(NavigationElement el)
{
el.Children = el.Children.OrderBy(x => x.Title).ToList();
if (el.Children != null)
{
foreach (var c in el.Children)
{
OrderChildren(c);
}
}
}
那這樣的東西呢?
public static class LinqExtension {
public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector) {
if (source == null) throw new ArgumentNullException("source");
foreach (var i in source) {
yield return i;
var children = childrenSelector(i);
if (children == null) continue;
foreach (var child in SelectManyRecursive(children, childrenSelector)) {
yield return child;
}
}
}
}
var orderedModel = unorderedModel
.OrderBy(x => x.SortOrder)
.SelectMany(x => new[] { x }.Union(
x.Children.SelectManyRecursive(y => y.Children)
.OrderBy(y => y.Parent.Title) // considering hierarchy
.ThenBy(y => y.Title)
))
.ToList();
對於您的案例,我將使用Linq使用來自帶有路徑和深度字段的“排序”層次結構中的方法。
首先,我對如何通過LINQ展平樹的回答中的一般樹遍歷助手。 :
public static partial class TreeUtils
{
public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = source.GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var elements = elementSelector(item);
if (elements == null) continue;
stack.Push(e);
e = elements.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
以及您的特定問題的解決方案:
var orderedModel = unorderedModel.Where(item => item.Parent == null).OrderBy(item => item.SortOrder)
.Expand(item => item.Children != null && item.Children.Any() ? item.Children.OrderBy(child => child.Title) : null)
.ToList();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.