2012-06-05 4 views
0

Я хотел бы получить несколько советов о том, как я могу построить дерево из списка элементов в эффективном способеПостроение дерева из списка предметов

public class Item 
    { 
     public Item(int id, int? parentId) 
     { 
      Id = id; 
      ParentId = parentId; 
     } 

     public int Id { get; private set; } 
     public int? ParentId { get; private set; } 
     public List<Item> SubItems { get; set; } 
    } 

    private Item BuildATree() 
    { 
     var items = new List<Item>() 
         { 
          new Item(1, null), 
          new Item(2, 1), 
          new Item(3, 1), 
          new Item(4, 1), 
          new Item(5, 2), 
          new Item(6, 2), 
          new Item(7, 4), 
          new Item(8, 7), 
          new Item(9, 1), 
         }; 

     //Build a tree out of list items 
    } 

В результате я ожидаю есть каждый элемент, находясь в его список

Не обязательно, используя тот же класс Item SubItems родителя, потому что Идентификаторы будут излишними, то

+2

Является ли это домашнее задание, так как эта структура стала горячей темой. http://stackoverflow.com/questions/10878268/recursive-reading-of-listobject, http://stackoverflow.com/questions/10827237/how-to-create-objects-with-retrieved-hierarchical-result-set –

+0

Это не домашнее задание, я не прошу решения, я прошу некоторых предложений, что было бы самым эффективным способом его решения. – Jeff

+1

Каков ваш * неэффективный способ, который заставляет вас искать эффективный? –

ответ

2

Решение, которое является достаточно эффективно

private void RecursiveBuilder(ref Item i, IEnumerable<Item> li) 
{ 
    var item = i; 
    i.SubItems = (from n in li where n.ParentId == item.Id select n).ToList(); 
    i.SubItems.ForEach(f => RecursiveBuilder(ref f, li)); 
} 
2

Я хотел бы использовать LINQ:

//Build a tree out of list items 
foreach (Item item in items) 
{ 
    item.SubItems = items.Where(i => i.ParentId.Value == item.Id).ToList(); 
} 

UPD:

Чтобы упростить перемещение элементов из одного родителя в другой, вам необходимо сохранить ссылку на родительский элемент в каждом элементе. Что-то вроде:

public class Item 
{ 
    public Item(int id, int? parentId) 
    { 
     Id = id; 
     ParentId = parentId; 
    } 

    public int Id { get; private set; } 
    public int? ParentId { get; private set; } 
    public List<Item> SubItems { get; set; } 

    private Item _parent; 
    public Item Parent 
    { 
     get { return _parent; } 
     set 
     { 
      if (_parent != null) 
       _parent.SubItems.Remove(this); 
      _parent = value; 
      if (_parent != null) 
       _parent.SubItems.Add(this); 
     } 
    } 
} 

Если вы реализуете таким образом, то просто заходящий новый пункт Parent данного свойства будет достаточно, чтобы изменить подпункты коллекции старого и новый родитель - но учтите, что вам также понадобится немного сложнее список инициализации.

+0

Может ли быть рекурсивным, а также удалять элементы из списка, если он был перемещен в другой элемент в качестве подпункта – Jeff

+0

@Jeff: см. Обновление –

+0

Элемент item в пунктах ... lol, thats должен быть самый похожий linq, который вы можете получить без нарушения зарезервированных ключевых слов: P – RhysW

1

Если вы не хотите/есть ссылка:

Dictionary<int,Item> dic = new Dictionary<int,Item>(); 
foreach(Item item in items) 
{ 
    Item parent; 
    if(item.ParentId!=null && dic.TryGetValue(item.ParentId, out parent)) 
     parent.SubItems.Add(item); 
    else 
     dic.Add(item.Id, item); 
} 
Item root = dic[1]; 

Я полагал, что всегда будет с идентификатором товара = 1, и это корень дерева.

Если вы хотите использовать новый класс без идентификаторов, создайте их, а не просто добавьте их родителям.

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