2014-08-27 16 views
7

tôi có một danh sách phẳng các loại như trong các lớp sauLập bản đồ một danh sách phẳng vào một danh sách thứ bậc với cha mẹ ID C#

public class FlatCategoryList 
{ 
    public List<FlatCategory> Categories { get; set; } 
} 
public class FlatCategory 
{ 
    public string ID { get; set; } 
    public string Name { get; set; } 
    public string ParentID { get; set; } 
} 

Tôi đang cố gắng để ánh xạ danh sách căn hộ của tôi trong danh mục cho một cấu trúc heirarical chẳng hạn như được hiển thị bên dưới:

public class HieraricalCategoryList 
{ 
    public List<Category> Categories { get; set; } 
} 
public class Category 
{ 
    public string ID { get; set; } 
    public string Name { get; set; } 
    public string ParentID { get; set; } 

    public List<Category> ChildCategories { get; set; } 
} 

Câu hỏi của tôi là cách tốt nhất để đạt được điều này, vì có thể có một số lượng vô hạn?

public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList) 
{ 
    var hieraricalCategoryList = new HieraricalCategoryList(); 

    //Do something here to map the flat category list to the hierarichal one... 

    return hieraricalCategoryList; 
} 
+0

Điều quan trọng là KHÔNG sử dụng đệ quy. –

+1

Chỉ cần một bên không cho lập trình tốt hơn. Bạn nên làm cho các thuộc tính của bạn IEnumerable vv, thay vì danh sách. Bằng cách này bạn có thể đặt bất cứ thứ gì kế thừa IEnumerable cho những người thích hợp như mảng, danh sách hoặc bất cứ thứ gì tùy chỉnh mà bạn tạo ra để kế thừa IEnumerable. –

+0

Nếu bạn phải thực hiện một loạt các ánh xạ tùy chỉnh khắp nơi, có một thư viện tuyệt vời cho cái gọi là AutoMapper này. http://automapper.org/ –

Trả lời

6
public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList) 
{ 
    var categories = (from fc in flatCategoryList.Categories 
         select new Category() { 
          ID = fc.ID, 
          Name = fc.Name, 
          ParentID = fc.ParentID 
         }).ToList(); 

    var lookup = categories.ToLookup(c => c.ParentID); 

    foreach(var c in categories) 
    { 
     // you can skip the check if you want an empty list instead of null 
     // when there is no children 
     if(lookup.Contains(c.ID)) 
      c.ChildCategories = lookup[c.ID].ToList(); 
    } 

    return new HieraricalCategoryList() { Categories = categories }; 
} 
+2

'if (lookup.Contains (c.ID))' là không cần thiết ở đây cả. Trong thực tế, nó có thể có hại, vì nó sẽ là thích hợp hơn để có một danh sách rỗng để 'null' cho bộ sưu tập con nếu một nút không có con. – Servy

+0

Đã thêm nhận xét về điều đó. – MarcinJuraszek

+0

@MarcinJuraszek Tôi đang gặp sự cố khi sử dụng mã của bạn, bạn có thể vui lòng câu hỏi của tôi tại https://stackoverflow.com/questions/28454466/create-hierarchical-structure-from-flat-list – Haris

1

Sử dụng giải pháp hai đường. Điều này giả định bộ sưu tập đầy đủ có thể phù hợp với bộ nhớ. Vượt qua đầu tiên quét danh sách các danh mục phẳng và xây dựng một từ điển Danh mục, được lập chỉ mục theo ID. Các bộ sưu tập con là tất cả sản phẩm nào tại thời điểm này, và tài sản mẹ là null. Sau đó, lần thứ hai vượt qua quét chúng một lần nữa, và xây dựng các bộ sưu tập con và đặt thuộc tính cha.

đang chưa được kiểm tra:

var final = new Dictionary<string, Category>(); 
var rootCategories = new List<Category>(); 

// Pass 1 
foreach (var flat in flatList) 
{ 
    Category cat = new Category() { ID = flat.ID, Name = flat.Name, parent = null } 
    cat.Children = new List<Category>(); 
    final[flat.ID] = cat; 
} 

// Pass 2 
foreach (var flat in flatList) 
{ 
    // find myself -- must exist 
    var self = final[flat.ID]; 

    // find parent -- may not exist 
    if (final.ContainsKey(flat.ParentID) 
    { 
    var parent = final[flat.ParentID]; 
    parent.Children.Add(self); 
    self.Parent = parent;  
    } 
    else 
    { 
    rootCategories.Add(self); 
    } 

} 

này sẽ có thời gian O (n) đang chạy, vì nó là hai quét tuyến tính, với một số tra cứu từ điển, mà là O (1).

+0

Việc sử dụng phương pháp mở rộng LINQ 'ToLookup' làm cho mã để làm điều này đơn giản hơn nhiều, trong khi đang hoạt động tương đương, như có thể thấy trong câu trả lời của tôi. – Servy

+0

Tôi phải thừa nhận tôi thích câu trả lời của MarcinJuraszek về phong cách và dễ đọc (ví dụ: tôi thấy nó trực quan hơn để tạo danh sách các mục 'category' và sau đó lặp lại thay vì vòng lặp trong danh sách gốc. để có được tất cả các con của một phụ huynh có thể làm cho mọi thứ neater.Nếu bạn chưa kiểm tra câu trả lời để xem cách chủ quan tốt hơn của việc làm điều. :) – Chris

+0

Tôi thích kiểu LINQ. Hãy xem xét câu trả lời trước LINQ này. –

4

Một cách rất dễ dàng và rất performant để làm cho chuyển đổi này là để tạo ra một tra cứu trong đó bạn ánh xạ giá trị ID để các nút đó nên con cái mà giá trị ID. Tra cứu này có thể được tạo ra trong một lần truyền các nút. Sau đó, bạn có thể lặp qua tất cả các nút một lần nữa gán bộ sưu tập con của chúng là giá trị của giá trị ID của chúng trong tra cứu.

Lưu ý rằng việc này đơn giản hơn nếu bản đồ tra cứu tìm đến đối tượng thuộc loại bạn đang chuyển đổi, không chuyển đổi.

var lookup = list.Categories 
    .Select(category => new Category() 
    { 
     ID = category.ID, 
     Name = category.Name, 
     ParentID = category.ParentID, 
    }) 
    .ToLookup(category => category.ParentID); 

foreach (var category in lookup.SelectMany(x => x)) 
    category.ChildCategories = lookup[category.ID].ToList(); 

var newList = new HieraricalCategoryList() 
{ 
    Categories = lookup[null].ToList(), 
}; 
Các vấn đề liên quan