在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 Children { get; set; } public virtual NavigationElement Parent { get; set; } public NavigationElement() { Children = new List(); } } 

如您所见,该类是自引用的。 从那时起,我正在创建一个带下拉的网站导航菜单(游戏中的层次结构)。

我正在努力订购这些物品。 我希望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

这是编译,但是当我运行代码时出现错误。 错误说:

至少有一个对象必须实现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 SelectManyRecursive(this IEnumerable source, Func> 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中的路径和深度字段使用Sort层次结构中的方法。

首先,从我的回答如何通过LINQ压平树的一般树遍历助手? :

 public static partial class TreeUtils { public static IEnumerable Expand(this IEnumerable source, Func> elementSelector) { var stack = new Stack>(); 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();