在LINQ

时间:2016-03-18 13:15:32

标签: c# 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。

3 个答案:

答案 0 :(得分:3)

您应该对所有子元素进行递归并对其进行排序。

有点像:

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);
        }
    }
}

答案 1 :(得分:0)

这样的事情怎么样?

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();

答案 2 :(得分:0)

我会根据您的情况使用Sort hierarchy with path and depth fields using Linq的方法。

首先,我对How to flatten tree via 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();