【问题标题】:(ID/ParentID) list to Hierarchical list(ID/ParentID) 列表到分层列表
【发布时间】:2012-02-23 07:49:27
【问题描述】:

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

如您所见,很多我不想要的项目仍在字典中

【问题讨论】:

  • 输出应该是什么类型的数据结构?
  • @Jon: 请参考我更新的问题
  • 但是List 不是分层数据结构。换句话说,你建议如何将List 变成图中的树?
  • @jon: 请参考我更新的问题,我可以通过简单的 foreach 语句将数据转回列表
  • 我不确定我是否理解您的问题。你希望你的输出是什么?

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


【解决方案1】:

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

这可以通过两行来完成:

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

【讨论】:

  • 我没想到。你是对的。创建层次结构不需要递归,只有 traversing 需要。
  • 遍历也不会。 :)
  • 刚刚用于类似的项目。漂亮的解决方案也很高效。
【解决方案2】:

对于分层数据,您需要递归 - 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 方法是如何在其自身内部被调用的。这就是构建层次结构的原因。

【讨论】:

  • 这比 OP 的原始代码性能差。字典方法要优越得多。
  • @user347805 @RamiShareef 我希望输出列表添加像 print |__|__11 如果那是一个孩子。如果那是父母,只需打印1。请帮忙。谢谢
  • @sarin 它以无限循环结束。休息条件是什么
【解决方案3】:

我需要这样的功能并比较这两种方法,发现方法 2 比第 1 快 :),目前在我的数据库卡或记录中是有限的,但第 1 方法需要 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 };
    }

方法二


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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多