简体   繁体   中英

How do I sort a list and its children and their children using linq?

I have a parent child relationship, something like:

public class MyType {

    public IList<MyType> Children {get;set;}
    public int Order {get;set;}

}

I would like to select the list so that each level is in order.

I can do this easily for the top level:

mylist.Children.OrderBy(x => x.Order)

But how do I do it for every set of Children?

The end result would be the list or type with all its children, and there children (and so on) all sorted correctly by Order.

Thanks.

You can do Recursive Order by adding one method to MyType like this:

public class MyType
{
    public IList<MyType> Childrens { get; set; }
    public int Order { get; set; }

    public void RecursiveOrder()
    {
        Childrens = Childrens.OrderBy(x => x.Order)
            .ToList();

        Childrens.ToList().ForEach(c => c.RecursiveOrder());
    }
} 

You can keep the children sorted if you use a SortedList as your underlying children collection. Then you can expose the Values property to get the values. Just key the items by their order when you add to the list.

eg,

public class MyType
{
    public MyType(int order)
    {
        this.order = order;
    }

    private int order;
    private SortedList<int, MyType> children = new SortedList<int, MyType>();

    public int Order { get { return order; } }
    public IList<MyType> Children { get { return children.Values; } }

    public void AddChild(MyType child)
    {
        children.Add(child.order, child);
    }
}

Otherwise, you'd probably want to sort the lists recursively. Using LINQ wouldn't be appropriate here. At best, LINQ would allow you to iterate over the children in a sorted order but it doesn't actually sort the underlying list unless you replace the list instance with the sorted version. If the underlying list has a Sort() method (which the generic List<T> has), then use that.

private List<MyType> children;
public void EnsureSorted()
{
    children.Sort();
    foreach (var child in children)
        child.EnsureSorted();
}

Starting off with a sorted list would be a lot easier however.

I agree with Jeff that the easiest answer is to store the data sorted if that is going to be your main access pattern. But lets say you really want to do this with Linq:

First off, if you knew you only wanted two levels of ordering, you could do something like this:

myList.Children.OrderBy(x => x.Order)
    .Select(c => c.Children.OrderBy(x => x.Order))

But what if what you really want is totally recursive ordering, all the way down?

delegate IEnumerable<MyType> RecursiveFunc(MyType data, RecursiveFunc self);
RecursiveFunc op = (data, func) => data.Children.OrderBy(x => x.Order)
    .Select(x => func(x, func));

IEnumerable<MyType> result = op(myList, op);

Just writing that makes my brain hurt, and I haven't tried running it, so best of luck! What it comes down to is passing a linq expression(lambda) to itself, to recursively apply itself down the tree.

这个

mylist.Children.OrderBy(x => x.Order).ThenBy( x => x.order).ToList();

If the end result simply has to be a list of children (instead of a list of parents with nested children), you can use a SelectMany

IEnumerable<Child> result  = parents
    .SelectMany(p => p.Children)
    .OrderBy(child => child.Order);

This can be done by selecting the data and sorting the Children list for each item.

IList<MyType> myTypeList = ... //Populated

var sortedList = myTypeList.Select(t =>
{ 
    t.Children = t.Children.OrderBy(c => c.Order);
    return t;
}).ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM