【问题标题】:Linq to build hierarchical listLinq 构建分层列表
【发布时间】:2010-01-07 18:44:42
【问题描述】:

我有一个从数据库中检索一组记录的方法。

我将这些数据映射到一个业务对象——我们称之为业务对象 ProcessModel。 ProcessModel 中的一个属性是一个列表,称为 ProcessChildren。属性为 List。

因此,数据由各种字段/属性链接。分层列表顶部有一个对象,然后该对象的 ProcessChildren 属性中有多个对象,这些对象的 ProcessChildren 属性中有多个对象等。

无论如何,我编写了相当多的代码来遍历返回的数据集,并构建分层列表,然后我将其绑定到 Silverlight 中的 TreeView。

如果有人可以为我提供一种更清洁、更简单的方法来执行此操作,我将非常感激,无论是使用 linq,还是使用 linq 或通过扩展方法的其他方法。

我已经包含了我当前使用的代码,希望能更好地说明我想要实现的目标。

var processes = new List<Process>();

        var rootLevelProcesses = new List<Process>();

        var allProcesses = new List<Process>();

        foreach (Process process in e.Results)
        {
            process.ProcessChildren = new List<Process>();

            if (process.ParentId > 0 || (process.ParentId == 0 && process.EntityId == 1))
            {
                allProcesses.Add(process);
            }
        }

        var rootProcess =
                    (from parent in e.Results
                     where parent.EntityType == 1 && parent.ContainerLevel <= 1
                     select parent).FirstOrDefault();

        processes.Add(rootProcess);

        var level2Processes = (from parent in allProcesses
                               where parent.EntityType == 1 && parent.ContainerLevel == 2
                               select parent).ToList();

        foreach (Process process in level2Processes)
        {
            var level3Processes = (from parent in allProcesses
                                   where parent.EntityType == 1 && parent.ContainerLevel == 3
                                   select parent).ToList();

            process.ProcessChildren = level3Processes;
        }

        processes[0].ProcessChildren = level2Processes;

        foreach (Process process in processes)
        {
            if (process.ProcessChildren != null && process.ProcessChildren.Count > 0)
            {
                foreach (Process level1 in process.ProcessChildren)
                {
                    if (level1.EntityType == 1)
                    {
                        var children =
                        (from child in allProcesses
                         where child.ParentId == level1.EntityId
                         select child).ToList();

                        level1.ProcessChildren = children;

                        foreach (Process level2 in level1.ProcessChildren)
                        {
                            if (level2.EntityType == 1)
                            {
                                children =
                            (from child in allProcesses
                             where child.ParentId == level2.EntityId
                             select child).ToList();

                                level2.ProcessChildren = children;

                                foreach (Process level3 in level2.ProcessChildren)
                                {
                                    if (level3.EntityType == 1)
                                    {
                                        children =
                                    (from child in allProcesses
                                     where child.ParentId == level3.EntityId
                                     select child).ToList();

                                        level3.ProcessChildren = children;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

【问题讨论】:

    标签: c# .net linq silverlight


    【解决方案1】:

    This related post 可能会有所帮助....

    更新:下面是支持 cmets 的代码...您需要进行编辑以支持您自己的类。

    public class Proc
    {
        public System.Diagnostics.Process RealProc;
        public List<Proc> SubProcs = null;
    }
    
    void Main()
    {
        var Processes = from p in System.Diagnostics.Process.GetProcesses() select new Proc { RealProc = p, SubProcs = null };
        while (Processes.Any(pr => pr.SubProcs == null))
        {
            foreach(Proc pr in Processes)
            {
                pr.RealProc.Id.Dump();
                pr.SubProcs = Processes.Where(prx => prx.RealProc.ParentId == pr.Id).ToList();  // doesn't work because no ParentId
            }
        }
    }
    

    【讨论】:

    • 谢谢 - 但我不确定这是否能解决我的问题。原因是那个人似乎在做我经常看到的事情 - 有顶级项目,然后是项目的子级。就我而言,它是动态的,基于列表中的每个项目。一个项目可能有一个孩子,然后那个孩子可能有三个孩子,然后其中一个孩子可能有一个孩子等等......
    • 好吧,我认为您可以将某些内容放入循环中...例如(伪代码): while(procs.Any(p => p.SubProcs == null) { foreach where proc.SubProcs = null { proc.SubProcs = ; } } - 这将递归地找到所有...请注意,分配应该为叶进程返回一个空列表以避免无限循环。跨度>
    • 顺便说一句,我没有在 Process 上看到“ParentId”属性...那在哪里?如果我能弄清楚,那么我可以发布实际的工作代码
    • 有一个 ParentId 属性。因此,我将数据链接在一起的方式是链接 ParentId 和 EntityId 属性。因此,孩子的父母将有一个与孩子的 ParentId 值匹配的 EntityId(数值)。这能回答你的问题吗?
    • 哦,我明白了......它必须是一个自定义类,而不是标准 System.Diagnostics.Process 类,这是我假设的......我会用我的一些代码修改我的帖子如果 .NET 标准 Process 类有 ParentID,认为它会工作......在这种情况下,主要属性只是 Id。
    【解决方案2】:

    我想这个答案有点晚了,但是就这样吧。

    尝试使用.LookUp(...) 扩展方法和递归 lambda 表达式:

    var lookup = e.Results.ToLookup(x => x.ParentId);
    
    Action<IEnumerable<Process>> addChildren = null;
    addChildren = ps =>
    {
        foreach (var p in ps)
        {
            p.ProcessChildren = lookup[p.EntityId].ToList();
            addChildren(p.ProcessChildren);
        }
    };
    
    var rootProcesses = e.Results.Where(x => x.ParentId == 0);
    
    addChildren(rootProcesses);
    

    这适用于我创建的测试数据。我没有使用ContainerLevel 属性,因为ParentId 关系隐式定义了级别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-15
      • 1970-01-01
      • 2019-09-27
      • 1970-01-01
      • 1970-01-01
      • 2017-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多