2015-09-12 4 views
1

Извините, если это задано в другом месте, однако я искал подходящий ответ, однако большая часть информации, которую я нашел, позволяет использовать только один дочерний элемент.Список заказов с дочерними элементами

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

public class InputClass 
{ 
    public int id { get; set; } 
    public string text { get; set; } 
    public string icon { get; set; } 
    public int? parentId { get; set; } 

} 

, и я стараюсь, чтобы преобразовать его в список следующего вида:

public class OutputClass 
{ 
    public int id { get; set; } 
    public string text { get; set; } 
    public string icon { get; set; } 
    public List<OutputClass> children { get; set; } 
} 

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

В качестве примера - в следующем списке:

var inputList = new List<InputClass>(); 
inputList.Add(new InputClass() { id = 1, text = "Item #1"}); 
inputList.Add(new InputClass() { id = 2, text = "Item #2" }); 
inputList.Add(new InputClass() { id = 3, text = "Item #3" }); 
inputList.Add(new InputClass() { id = 4, text = "SubItem #1", parentId = 1 }); 
inputList.Add(new InputClass() { id = 5, text = "SubItem #2", parentId = 1 }); 
inputList.Add(new InputClass() { id = 6, text = "SubItem #3", parentId = 2 }); 

должен выводиться как:

Item #1 
----SubItem #1 
----SubItem #2 
Item #2 
----SubItem #3 
Item #3 

количество элементов в списке детей не должны ограничиваться только один. Любые идеи о том, как правильно сортировать их?

ответ

2
var mapping = inputList 
    // for each input element, capture the parent id and create the respective output object 
    .Select(input => new { 
     ParentId = input.parentId, 
     Obj = new OutputClass() { id = input.id, text = input.text, icon = input.icon, children = new List<OutputClass>() } 
    }) 
    // create a dictionary so we can look up the elements by id 
    .ToDictionary(x => x.Obj.id); 

// create target list 
List<OutputClass> output = new List<OutputClass>(); 

// loop through all elements 
foreach (var x in mapping.Values) 
{ 
    // if the element has a parent id 
    if (x.ParentId.HasValue) 
    { 
     // find the parent object … 
     OutputClass parentObj = mapping[x.ParentId.Value].Obj; 
     // … and add this object to the parent’s child list 
     parentObj.children.Add(x.Obj); 
    } 
    else 
    { 
     // otherwise this is a root element, so add it to the target list 
     output.Add(x.Obj); 
    } 
} 

Результатом будет список, который содержит элементы ввода с соответствующим hiearchy.

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


Чтобы произвести вывод, можно написать рекурсивную функцию:

public static void Print(IEnumerable<OutputClass> elements, string indent="") 
{ 
    foreach (OutputClass element in elements) 
    { 
     Console.WriteLine("{0}{1} {2}", indent, element.id, element.text); 
     Print(element.children, indent + " "); 
    } 
} 

Для вашего входа, это приводит к следующему результату:

1 Item #1 
    4 SubItem #1 
    5 SubItem #2 
2 Item #2 
    6 SubItem #3 
3 Item #3 

И точно так же, как пример, следующий список ввода производит выход ниже, используя один и тот же код преобразования, как описано выше:

var inputList = new List<InputClass>() 
{ 
    new InputClass() { id = 1, text = "Item 1" }, 
    new InputClass() { id = 2, text = "Item 2" }, 
    new InputClass() { id = 3, text = "Item 3" }, 
    new InputClass() { id = 4, text = "SubItem 1.1", parentId = 1 }, 
    new InputClass() { id = 5, text = "SubItem 1.2", parentId = 1 }, 
    new InputClass() { id = 6, text = "SubItem 2.1", parentId = 2 }, 
    new InputClass() { id = 7, text = "SubItem 2.2", parentId = 2 }, 
    new InputClass() { id = 8, text = "SubItem 1.2.1", parentId = 5 }, 
    new InputClass() { id = 9, text = "SubItem 1.2.2", parentId = 5 }, 
    new InputClass() { id = 10, text = "SubItem 1.2.1.1", parentId = 8 }, 
    new InputClass() { id = 11, text = "SubItem 2.1.1", parentId = 6 }, 
    new InputClass() { id = 12, text = "SubItem 2.1.1.1", parentId = 11 }, 
    new InputClass() { id = 13, text = "SubItem 2.1.1.1.1", parentId = 12 }, 
    new InputClass() { id = 14, text = "SubItem 2.1.1.1.2", parentId = 12 } 
}; 

Выход:

1 Item 1 
    4 SubItem 1.1 
    5 SubItem 1.2 
    8 SubItem 1.2.1 
     10 SubItem 1.2.1.1 
    9 SubItem 1.2.2 
2 Item 2 
    6 SubItem 2.1 
    11 SubItem 2.1.1 
     12 SubItem 2.1.1.1 
     13 SubItem 2.1.1.1.1 
     14 SubItem 2.1.1.1.2 
    7 SubItem 2.2 
3 Item 3 
+0

Отличный ответ и объяснение. –

0

Следующий код должен напечатать то, что вам нужно:

static void Main(string[] args) 
{ 
    var inputList = new List<InputClass>(); 
    inputList.Add(new InputClass() { id = 1, text = "Item #1" }); 
    inputList.Add(new InputClass() { id = 2, text = "Item #2" }); 
    inputList.Add(new InputClass() { id = 3, text = "Item #3" }); 
    inputList.Add(new InputClass() { id = 4, text = "SubItem #1", parentId = 1 }); 
    inputList.Add(new InputClass() { id = 5, text = "SubItem #2", parentId = 1 }); 
    inputList.Add(new InputClass() { id = 6, text = "SubItem #3", parentId = 2 }); 

    var outputList = inputList 
     .Where(i => !i.parentId.HasValue) // Just get the parents 
     .Select(i => new OutputClass() 
    { 
     id = i.id, 
     icon = i.icon, 
     text = i.text, 
     children = inputList 
     .Where(x => x.parentId == i.id) 
     .Select(x => new OutputClass() 
     { 
      id = x.id, 
      icon = x.icon, 
      text = x.text, 
     }).ToList() 
    }).ToList(); 


    foreach (var output in outputList) 
    { 
     Console.WriteLine(output.text); 
     output.children.ForEach(c => Console.WriteLine($"\t {c.text}")); 
    } 

    Console.ReadLine();  
} 

Выход:

Item #1 
     SubItem #1 
     SubItem #2 
Item #2 
     SubItem #3 
Item #3 
+0

Это решение O (N²) и только поддерживает двухуровневая иерархия. – poke

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