(ID / ParentID)列表到分层列表

时间:2012-02-23 07:49:28

标签: c# list linq-to-objects hierarchical-data

MyClassID ParentIDList<MyClass>组成Children

我有MyClass这样的列表

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

输出(分层列表)为List<MyClass>

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

9 __10

在linq中实现这一目标的最简单方法是什么? P.S。:ParentID没有排序

修改:
我的尝试:

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

初始化样本数据并尝试访问分层数据

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

正如你所看到的,很多我不想要的东西仍然在字典中

3 个答案:

答案 0 :(得分:38)

如果您在过滤之前构建父子关系,则此处不需要递归。由于列表成员保持相同的对象,只要您将列表的每个成员与其直接子项相关联,就会构建所有必要的关系。

这可以分为两行:

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

答案 1 :(得分:15)

对于分层数据,您需要递归 - foreach循环是不够的。

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与您使用的列表相同。注意SetChildren方法本身是如何调用的。这就构成了层次结构。

答案 2 :(得分:1)

我需要这样的功能并比较两种方法并找到方法2nd比第一种方法快:),现在我的数据库卡或记录有限但第一种方法需要4倍的时间才能完成。

对于那些有时间意识的人来说,这可能会有所帮助。

1方法


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

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