2016-03-27 4 views
1

У меня небольшая иерархия. Пример:Иерархическая сортировка данных C#

лицо:

public class MyClass 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public int ParentID { get; set; } 
} 

Мои данные иерархии выглядеть следующим образом:

Id = 1 Name = Item1 ParentId = NULL 
Id = 2 Name = Item2 ParentId = 1 
Id = 3 Name = Item3 ParentId = 2 
Id = 4 Name = Item4 ParentId = 2 
Id = 5 Name = Item5 ParentId = 3 

Проблема в том, мне нужно сортировать его, что дочерние узлы должны быть после его непосредственного родителя. Нижеследующий пример должен выглядеть так:

Id = 1 Name = Item1 ParentId = NULL 
Id = 2 Name = Item2 ParentId = 1 
Id = 3 Name = Item3 ParentId = 2 
// the elements with parentID = 3 
       Id = 5 Name = Item5 ParentId = 3 
    //continue 
    Id = 4 Name = Item4 ParentId = 2 

Любые рекламные объявления?

+2

Что вы сделали до сих пор? Отправьте свою попытку. – Saleem

+1

Вы уверены, что пример выводится правильно, потому что элемент с Id = 4 не находится рядом с его родителем (с id = 2)? – Nasreddine

+0

Вы можете поместить свои данные в «DataTable» и отсортировать их как в первой части этой статьи: https://weblogs.asp.net/stevewellens/from-table-to-treeview-displaying-hierarchies –

ответ

0

Предполагая, что у вас есть _list из MyClass объектов, а затем отсортировать его сначала на Name поля, а затем на ParentId поля, как показано ниже, с помощью LINQ:

_list.OrderBy(L=>L.Name).ThenBy(L=>L.ParentId); 

Надеется, что это может помочь.

+0

Не так ли просто сортировать по имени и никогда не ParentId, потому что нет предметов с тем же именем? – Andrew

+0

Тогда вы можете просто отсортировать по именам. С уважением, –

+0

Я тебя не понял. Ваш код будет перечислять эти элементы в том порядке, в котором они указаны в вопросе, упорядоченном по имени ... – Andrew

0

Попытайтесь это Я предполагаю, что 1-й, который вы хотите заказать по родителям, и у каждого родителя, которого хотите сортировать по id.

myClassList.OrderBy(parent=>parent.ParentId).ThenBy(parent=>parent.Id); 
+0

Я думал об этом, но это работает только с двумя уровнями, я думаю. Элемент с 'Id = 5' не будет отображаться прямо под его родителем, но в конце. – Andrew

0

Попробуйте этот рекурсивный код

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyClass.data = new List<MyClass>() { 
       new MyClass() { ID = 1, Name = "Item1", ParentID = null}, 
       new MyClass() { ID = 2, Name = "Item2", ParentID = 1 }, 
       new MyClass() { ID = 3, Name = "Item3", ParentID = 2 }, 
       new MyClass() { ID = 4, Name = "Item4", ParentID = 2 }, 
       new MyClass() { ID = 5, Name = "Item5", ParentID = 3 } 
      }; 

      MyClass myClass = new MyClass(); 
      myClass.GetData(null, 0); 
      Console.ReadLine(); 
     } 
    } 
    public class MyClass 
    { 
     public static List<MyClass> data = null; 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public int? ParentID { get; set; } 

     public void GetData(int? id, int level) 
     { 
      List<MyClass> children = data.Where(x => x.ParentID == id).ToList(); 

      foreach (MyClass child in children) 
      { 
       Console.WriteLine(" {0} ID : {1}, Name : {2}, Parent ID : {3}", new string(' ',4 * level),child.ID, child.Name, child.ParentID); 
       GetData(child.ID, level + 1); 
      } 

     } 
    } 
} 
0

Здесь у вас есть способ сделать это. Как вы можете видеть, я переопределил метод ToString и добавил еще несколько случаев.

public class MyClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int? ParentId { get; set; } 

    public override string ToString() 
    { 
     return string.Format("{0}: {1} - {2}", Id, Name, ParentId); 
    } 
} 

class Program 
{ 

    static void Main(string[] args) 
    { 
     List<MyClass> list = new List<MyClass>(); 
     list.Add(new MyClass { Id = 1, Name = "Item1", ParentId = null }); 
     list.Add(new MyClass { Id = 2, Name = "Item2", ParentId = 1 }); 
     list.Add(new MyClass { Id = 3, Name = "Item3", ParentId = 2 }); 
     list.Add(new MyClass { Id = 4, Name = "Item4", ParentId = 2 }); 
     list.Add(new MyClass { Id = 5, Name = "Item5", ParentId = 3 }); 
     list.Add(new MyClass { Id = 6, Name = "Item6", ParentId = 1 }); 
     list.Add(new MyClass { Id = 7, Name = "Item7", ParentId = null }); 
     list.Add(new MyClass { Id = 8, Name = "Item8", ParentId = 2 }); 
     list.Add(new MyClass { Id = 9, Name = "Item9", ParentId = 6 }); 
     list.Add(new MyClass { Id = 10, Name = "Item10", ParentId = 7 }); 

     foreach(var item in list.Where(x => !x.ParentId.HasValue).OrderBy(x => x.Id)) 
      ProcessItem(item, list, 0); 

     Console.ReadKey(); 

    } 

    private static void ProcessItem(MyClass item, List<MyClass> list, int level) 
    { 
     Console.WriteLine("{0}{1}", new string(' ', level * 2), item.ToString()); 
     foreach (var subitem in list.Where(x => x.ParentId == item.Id).OrderBy(x => x.Id)) 
      ProcessItem(subitem, list, level + 1); 
    } 
} 

Будет что-то вроде этой работы для вас?

Если вам нужен фактический упорядоченный список, попробуйте следующее:

foreach (var item in OrderList(list)) 
    Console.WriteLine(item.ToString()); 

(...) 

private static List<MyClass> OrderList(List<MyClass> list) 
{ 
    List<MyClass> orderedList = new List<MyClass>(list.Count()); 
    foreach (var item in list.Where(x => !x.ParentId.HasValue).OrderBy(x => x.Id)) 
     AddItem(item, list, orderedList); 

    return orderedList; 
} 

private static void AddItem(MyClass item, List<MyClass> list, List<MyClass> orderedList) 
{ 
    orderedList.Add(item); 
    foreach (var subitem in list.Where(x => x.ParentId == item.Id).OrderBy(x => x.Id)) 
     AddItem(subitem, list, orderedList); 
} 
0

Следующая следует сделать трюк (и показать некоторые более высокую производительность, так как мы сохранить иерархию в результате поиска, вместо поиска на IEnumerable на летать):

public List<MyClass> SortHierarchically(IEnumerable<MyClass> myClasses) 
{ 
    if(myClasses == null) 
     return new List<MyClass>(); 

    var myClassesByParentId = myClasses.ToLookup(mc => mc.ParentId); 
    var result = new List<MyClass>(myClasses.Count()); 

    int? currentParentId = null; 
    MyClass currentItem = myClassesByParentId[currentParentId].Single(); 
    result.Add(currentItem); 
    currentParentId = currentItem.Id; 

    if(myClassesByParentId.Contains(currentParentId)) 
     result.AddRange(myClassesByParentId[currentParentId].SelectMany(mc => GetAllSortedChildren(mc, myClassesByParentId))); 

    return result; 
} 

public List<MyClass> GetAllSortedChildren(MyClass parent, ILookup<int?, MyClass> myClassesByParentId) 
{ 
    var result = new List<MyClass>() { parent }; 
    if(myClassesByParentId.Contains(parent.Id)) 
     retsult.AddRange(myClassesByParentId[parent.Id].SelectMany(mc => GetAllSortedChildren(mc, myClassesByParentId))); 

    return result; 
} 

было бы интересно найти способ сортировки это с помощью стандартного LINQ, с каким-то умным компаратором или таким.

Смежные вопросы