2012-02-23 27 views
9

MyClass gồm IDParentIDList<MyClass> như Children(ID/ParentID) Danh mục vào danh sách phân cấp

Tôi có danh sách các MyClass như

ID ParentID 
1 0 
2 7 
3 1 
4 5 
5 1 
6 2 
7 1 
8 6 
9 0 
10 9 

Output (danh sách phân cấp) này như List<MyClass>

1 __ 3 
|__ 5__ 4 
|__ 7__ 2__ 6__ 8 
    |__ 11 

9 __10 

Cách đơn giản nhất để đạt được điều này trong LINQ là gì?
PS: ParentID không sắp xếp

Edit:
thử của tôi:

class MyClass 
{ 
    public int ID; 
    public int ParentID; 
    public List<MyClass> Children = new List<MyClass>(); 
    public MyClass(int id, int parent_id) 
    { 
     ID = id; 
     ParentID = parent_id; 
    } 
} 

khởi tạo dữ liệu mẫu và cố gắng đạt được dữ liệu phân cấp

List<MyClass> items = new List<MyClass>() 
{ 
    new MyClass(1, 0), 
    new MyClass(2, 7), 
    new MyClass(3, 1), 
    new MyClass(4, 5), 
    new MyClass(5, 1), 
    new MyClass(6, 2), 
    new MyClass(7,1), 
    new MyClass(8, 6), 
    new MyClass(9, 0), 
    new MyClass(10, 9), 
    new MyClass(11, 7), 
}; 

Dictionary<int, MyClass> dic = items.ToDictionary(ee => ee.ID); 

foreach (var c in items) 
    if (dic.ContainsKey(c.ParentID)) 
     dic[c.ParentID].Children.Add(c); 

như bạn có thể thấy, rất nhiều các mục tôi không muốn vẫn còn trong từ điển

+0

loại cấu trúc dữ liệu nên sản lượng được? – Jon

+0

@Jon: Vui lòng tham khảo câu hỏi được cập nhật của tôi –

+0

Nhưng một 'Danh sách' không phải là cấu trúc dữ liệu phân cấp. Nói cách khác, làm thế nào để bạn đề xuất biến một 'Danh sách' thành cây hình? – Jon

Trả lời

13

Đối với dữ liệu phân cấp, bạn cần đệ quy - vòng lặp foreach sẽ không đủ.

Action<MyClass> SetChildren = null; 
SetChildren = parent => 
    { 
     parent.Children = items 
      .Where(childItem => childItem.ParentID == parent.ID) 
      .ToList(); 

     //Recursively call the SetChildren method for each child. 
     parent.Children 
      .ForEach(SetChildren); 
    }; 

//Initialize the hierarchical list to root level items 
List<MyClass> hierarchicalItems = items 
    .Where(rootItem => rootItem.ParentID == 0) 
    .ToList(); 

//Call the SetChildren method to set the children on each root level item. 
hierarchicalItems.ForEach(SetChildren); 

items là cùng danh sách bạn sử dụng. Chú ý phương thức SetChildren được gọi trong chính nó. Đây là những gì xây dựng hệ thống phân cấp.

+1

Điều này ít hiệu quả hơn mã ban đầu của OP. Phương pháp từ điển vượt trội hơn rất nhiều. –

+0

Đẹp user347805, Nó làm việc cho tôi – Shailesh

+0

Đây là mẹo hay .. !! nó làm việc cho tôi quá .. !! –

32

Không cần phải đệ quy ở đây nếu bạn xây dựng mối quan hệ cha-con trước khi lọc. Vì các thành viên của danh sách vẫn là các đối tượng tương tự, miễn là bạn liên kết từng thành viên của danh sách với các con ngay lập tức của nó, tất cả các mối quan hệ cần thiết sẽ được xây dựng.

này có thể được thực hiện trong hai dòng:

items.ForEach(item => item.Children = items.Where(child => child.ParentID == item.ID) 
              .ToList()); 
List<MyClass> topItems = items.Where(item => item.ParentID == 0).ToList(); 
+0

Tôi không nghĩ về điều đó. Bạn hoàn toàn đúng. Việc tạo cấu trúc phân cấp không yêu cầu đệ quy, chỉ ** di chuyển ngang **. – user347805

+0

Truyền tải cũng không. :) – DiVan

+0

Chỉ cần sử dụng cho một dự án tương tự. Giải pháp đẹp và hiệu quả quá. –

1

Tôi đã yêu cầu chức năng như vậy và so sánh cả hai phương pháp và tìm phương pháp thứ 2 là nhanh hơn :) 1, ngay bây giờ trong thẻ cơ sở dữ liệu của tôi hoặc các hồ sơ được giới hạn nhưng Phương pháp thứ nhất lấy thêm 4 lần nữa để hoàn thành.

có thể là điều này có thể giúp cho những người có ý thức về thời gian.

1 phương pháp


public JsonResult CardData() 
    { 
     var watch = System.Diagnostics.Stopwatch.StartNew(); 
     OrgChartWithApiContext db = new OrgChartWithApiContext(); 

     var items = db.Cards.ToList(); 
     Action<Card> SetChildren = null; 
     SetChildren = parent => { 
      parent.Children = items 
       .Where(childItem => childItem.ParentId == parent.id) 
       .ToList(); 

      //Recursively call the SetChildren method for each child. 
      parent.Children 
       .ForEach(SetChildren); 
     }; 

     //Initialize the hierarchical list to root level items 
     List<Card> hierarchicalItems = items 
      .Where(rootItem => !rootItem.ParentId.HasValue) 
      .ToList(); 

     //Call the SetChildren method to set the children on each root level item. 
     hierarchicalItems.ForEach(SetChildren); 
     watch.Stop(); 
     var timetaken = watch.ElapsedMilliseconds; 

     return new JsonResult() { Data = hierarchicalItems, ContentType = "Json", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
    } 

phương pháp 2


public JsonResult Card2Data() 
    { 
     var watch = System.Diagnostics.Stopwatch.StartNew(); 
     OrgChartWithApiContext db = new OrgChartWithApiContext(); 
     var items = db.Cards.ToList(); 
     List<Card> topItems = items.Where(item => !item.ParentId.HasValue).ToList(); 
     topItems.ForEach(item => item.Children = items.Where(child => child.ParentId == item.id).ToList()); 
     watch.Stop(); 
     var timetaken = watch.ElapsedMilliseconds; 
     return new JsonResult() { Data = topItems, ContentType = "Json", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
    } 
Các vấn đề liên quan