带子项的订购列表

时间:2015-09-12 23:31:25

标签: c# linq

如果在其他地方被问到这个问题,我会一直在寻找合适的答案,但是我发现的大多数信息都只允许单个子项目。

我试图编写一个在树形视图界面中显示信息的程序。我面临的问题是我从后端DB读取以下课程:

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; }
}

正如您所看到的,子属性将在找到它的父项时填充。

作为示例 - 以下列表:

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 个答案:

答案 0 :(得分:4)

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);
    }
}

结果将是一个包含具有相应层次结构的输入元素的列表。

这是线性时间的解决方案,它只会循环两次项目。此外,它还支持多个级别的层次结构,因此您可以拥有父ID 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

答案 1 :(得分: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