How to sort a list of both his 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 a 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 to do this for each set of children?

The end result will be a list or type with all its children, and there the children (etc.) will be correctly sorted in order.

Thanks.

+3
source share
5 answers

You can perform a recursive order by adding one of the methods to MyType as follows:

 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()); } } 
+6
source

You can save the sorting of children if you use SortedList as the main collection for children. You can then open the Values property to get the values. Just add order elements to the list when adding 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 probably want to sort the lists recursively. Using LINQ is not suitable here. In the best case, LINQ will allow you to iterate over the children in sorted order, but will not actually sort the base list unless you replace the list instance with the sorted version. If the underlying list has a Sort() method (which has a common List<T> ), use it.

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

Running with a sorted list will be much easier.

+2
source

I agree with Jeff that the simplest answer is to store the sorted data if this is your main access pattern. But let's say you really want to do this with Linq:

First of all, if you knew that you want only two levels of order, you can do something like this:

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

But what if you really want a completely recursive order, right up to?

 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 what makes my brain hurt, and I didn’t try to run it, so I’m more lucky! It is about passing the linq (lambda) expression to itself in order to apply itself to the tree recursively.

+1
source

try this one

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

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

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

Source: https://habr.com/ru/post/1434722/


All Articles