将flat collection转换为hierarchal集合的递归方法?

时间:2013-01-11 04:28:40

标签: c# linq entity-framework

我已经坚持这个问题几天了,并且会感谢一些想法或帮助解决它。 我有一组对象

 public class Hierarchy
{
    public Hierarchy(string iD, string name, int level, string parentID, string topParent)
    {
        ID = iD;
        Name = name;
        Level = level;
        ParentID = parentID;
        Children = new HashSet<Hierarchy>();
    }
    public string ID { get; set; }
    public string Name{ get; set; }
    public int Level { get; set; }
    public string ParentID { get; set; }
    public ICollection<Hierarchy> Children { get; set; }
}

Linq查询到我的实体的数据是:

ID      Name     Level ParentID
295152  name1    1     null
12345   child1   2     295152
54321   child2   2     295152
44444   child1a  3     12345
33333   child1b  3     12345
22222   child2a  3     54321
22221   child2b  3     54321
22002   child2c  3     54321
20001   child2a2 4     22222
20101   child2b2 4     22222

这些数据可能会扩展到未知的深度(我只显示4)。 最终,我会有一个Hierarchy对象,其中包含多个子对象的集合,而这些对象又可能包含多个子对象的集合......等等...... 总会只有一个顶级对象。

我正试图在这个项目中尽可能多地使用Linq。

这显然需要某种递归方法,但我被卡住了。任何想法或帮助将不胜感激。

TIA

2 个答案:

答案 0 :(得分:4)

实际上,迭代解决方案可能要容易得多。以下是步骤:

  1. 根据ID
  2. 将所有节点哈希到字典中
  3. 第二次循环,并将每个节点添加到其父节点的子列表
  4. 看起来像这样:

    Hierarchy CreateTree(IEnumerable<Hierarchy> Nodes)
    {
        var idToNode = Nodes.ToDictionary(n => n.ID, n => n);
    
        Hierarchy root;
        foreach (var n in Nodes)
        {
            if (n.ID == null)
            {
                if (root != null)
                {
                    //there are multiple roots in the data
                }
                root = n;
                continue;
            }
    
            Hierarchy parent;
            if (!idToNode.TryGetValue(n.ID, parent))
            {
                //Parent doesn't exist, orphaned entry
            }
    
            parent.Children.Add(n);
        }
    
        if (root == null)
        {
            //There was no root element
        }
        return root;
    }
    

    您的数据格式存在几个明显可能的错误情况。由你来决定它们是什么。

    通常,总会有迭代解决方案和递归解决方案。特定问题会改变哪一个更容易。

答案 1 :(得分:4)

你可以试试这个递归函数:

void PopulateChildren(Hierarchy root, ICollection<Hierarchy> source)
{
    foreach (var hierarchy in source.Where(h => h.ParentID == root.ParentID))
    {
        root.Children.Add(hierarchy);
        PopulateChildren(root, source);
    }
}

您可以这样使用:

ICollection<Hierarchy> hierarchies = new List<Hierarchy>(); // source

// Get root
var root = hierarchies.Single(h => h.Level == 1);

// Populate children recursively
PopulateChildren(root, hierarchies);