Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-递归分组_C#_.net_Recursion - Fatal编程技术网

C#-递归分组

C#-递归分组,c#,.net,recursion,C#,.net,Recursion,我有一个IGroup类型的对象列表。这些可以嵌套到umlimited级别,我试图在从数据库检索它们之后对它们进行分组。我不知道如何递归地将所有组添加到正确的父组。任何父级为null的组都是顶级组。我不能保证他们从数据库中出来的顺序 public interface IGroup { string ID { get; set; } string Name { get; set; } string ParentID { get; set; } IList<IGroup>

我有一个IGroup类型的对象列表。这些可以嵌套到umlimited级别,我试图在从数据库检索它们之后对它们进行分组。我不知道如何递归地将所有组添加到正确的父组。任何父级为null的组都是顶级组。我不能保证他们从数据库中出来的顺序

public interface IGroup {
  string ID { get; set; }
  string Name { get; set; }
  string ParentID { get; set; }
  IList<IGroup> Groups { get; set; }
  ...
我试着将它们归类为:

|Group1
|--Group1a
|--Group1b
|--|
   |--Group1bc
|Group2

有人想尝试递归地对它们进行分组吗?

您可以尝试按父id对它们进行排序,假设父组总是在子组之前创建。

您可以尝试按父id对它们进行排序,假设父组总是在子组之前创建。

按父id分组。(Linq:
GroupBy
),订单依据
ID


从一个空的根节点(ID:
null
)开始,并添加具有此ParentID的所有项目。对于已添加的任何项目,递归地继续此过程。

ParentID
分组(Linq:
GroupBy
),按
ID
排序


从一个空的根节点(ID:
null
)开始,并添加具有此ParentID的所有项。对于已添加的任何项,递归地继续此过程。

无需递归。即:

var lookup = items.ToDictionary(g => g.ID); // items is IEnumerable<IGroup>
foreach (var item in items.Where(g => g.ParentID != null)) {
    lookup[item.ParentID].Groups.Add(item);
}
var parents = items.Where(g => g.ParentID == null);
我的测试项目:

IEnumerable<IGroup> items = new List<IGroup>() {
    new Group() { ID = "g1", ParentID = null },
    new Group() { ID = "g2", ParentID = "g1" },
    new Group() { ID = "g3", ParentID = null },
    new Group() { ID = "g4", ParentID = "g3" },
    new Group() { ID = "g5", ParentID = "g4" },
    new Group() { ID = "g6", ParentID = "g5" }
};    
IEnumerable items=新列表(){
新组(){ID=“g1”,ParentID=null},
新组(){ID=“g2”,ParentID=“g1”},
新组(){ID=“g3”,ParentID=null},
新组(){ID=“g4”,ParentID=“g3”},
新组(){ID=“g5”,ParentID=“g4”},
新组(){ID=“g6”,ParentID=“g5”}
};    

无需递归。也就是说:

var lookup = items.ToDictionary(g => g.ID); // items is IEnumerable<IGroup>
foreach (var item in items.Where(g => g.ParentID != null)) {
    lookup[item.ParentID].Groups.Add(item);
}
var parents = items.Where(g => g.ParentID == null);
我的测试项目:

IEnumerable<IGroup> items = new List<IGroup>() {
    new Group() { ID = "g1", ParentID = null },
    new Group() { ID = "g2", ParentID = "g1" },
    new Group() { ID = "g3", ParentID = null },
    new Group() { ID = "g4", ParentID = "g3" },
    new Group() { ID = "g5", ParentID = "g4" },
    new Group() { ID = "g6", ParentID = "g5" }
};    
IEnumerable items=新列表(){
新组(){ID=“g1”,ParentID=null},
新组(){ID=“g2”,ParentID=“g1”},
新组(){ID=“g3”,ParentID=null},
新组(){ID=“g4”,ParentID=“g3”},
新组(){ID=“g5”,ParentID=“g4”},
新组(){ID=“g6”,ParentID=“g5”}
};    

从数据库中提取每个元素时,需要将其添加到其父元素中。因此,请保留一个字典以帮助查找父元素。如果在其父元素之前有子元素,则可以插入占位符,直到获得真实的元素

void BuildGroups()
{
   foreach( IGroup x /* obtained from database or a collection or wherever */ )
      AddGroup( x );
}

Dictionary<string,IGroup> _groups = new Dictionary<string,IGroup>;
string _parentGroupName = "PARENT";
void AddGroup( IGroup x )
{
    // locate (or create) parent and add incoming group
    IGroup parent;
    string parentID = x.ParentID ?? _parentGroupName;
    if( !groups.TryGetValue( parentID, out parent ) )
    {
       parent = new Group( parentID ); // SEE NOTE BELOW!
       _groups[parentID] = parent;
    }
    parent.Groups.Add( x );

    // locate (or insert) child, and make sure it's up to date
    IGroup child;
    if( groups.TryGetValue( x.ID, out child ) )
    {
       // We must have inserted this ID before, because we found one
       // of ITS children first.  If there are any other values besides
       // ParentID and ID, then copy them from X to child here.
    }
    else
    {
       // first time we've seen this child ID -- insert it
        _groups[x.ID] = x;
    }

}
注意:此实现在数据的一次内联传递中运行--您可以在从数据库检索元素时立即添加元素,并且只需对数据进行一次传递。这意味着您可以节省一些时间和内存。但作为回报,您需要能够分配一个类型为IGroup()的对象作为占位符,以防在其父对象之前检索到子对象。只有当您了解对象的顺序或分两次处理词典时,才能避免该要求,如其他答案所示


我使用sentinel值\u parentGroupName将顶级节点与所有其他节点保持在同一个集合中。如果愿意,您可以轻松更改此值,以便为顶级节点使用单独的集合。

从数据库提取每个元素时,需要将其添加到其父元素。因此,请保留一个字典以帮助查找parent、 如果子对象先于父对象,则可以插入占位符,直到获得真实对象

void BuildGroups()
{
   foreach( IGroup x /* obtained from database or a collection or wherever */ )
      AddGroup( x );
}

Dictionary<string,IGroup> _groups = new Dictionary<string,IGroup>;
string _parentGroupName = "PARENT";
void AddGroup( IGroup x )
{
    // locate (or create) parent and add incoming group
    IGroup parent;
    string parentID = x.ParentID ?? _parentGroupName;
    if( !groups.TryGetValue( parentID, out parent ) )
    {
       parent = new Group( parentID ); // SEE NOTE BELOW!
       _groups[parentID] = parent;
    }
    parent.Groups.Add( x );

    // locate (or insert) child, and make sure it's up to date
    IGroup child;
    if( groups.TryGetValue( x.ID, out child ) )
    {
       // We must have inserted this ID before, because we found one
       // of ITS children first.  If there are any other values besides
       // ParentID and ID, then copy them from X to child here.
    }
    else
    {
       // first time we've seen this child ID -- insert it
        _groups[x.ID] = x;
    }

}
注意:此实现在数据的一次内联传递中运行--您可以在从数据库检索元素时立即添加元素,并且只需对数据进行一次传递。这意味着您可以节省一些时间和内存。但作为回报,您需要能够分配一个类型为IGroup()的对象作为占位符,以防在其父对象之前检索到子对象。只有当您了解对象的顺序或分两次处理词典时,才能避免该要求,如其他答案所示


我使用sentinel值\u parentGroupName将顶级节点与其他所有节点保持在同一个集合中。如果愿意,您可以轻松更改此值,以便为顶级节点使用单独的集合。

这不是递归的,但这里有一个解决方案(假设您在名为
组的列表中拥有所有组)

var rootGroups=newlist();
var dic=组。ToDictionary(g=>g.ID);
foreach(组中的变量g)
{
if(g.ParentID==null)
{
根群。添加(g);
}
其他的
{
i组父母;
if(dic.TryGetValue(g.ParentID,out parent))
{
parent.Groups.Add(g);
}
}
}

这不是递归的,但这里有一个解决方案(假设您在名为
组的列表中拥有所有组)

var rootGroups=newlist();
var dic=组。ToDictionary(g=>g.ID);
foreach(组中的变量g)
{
if(g.ParentID==null)
{
根群。添加(g);
}
其他的
{
i组父母;
if(dic.TryGetValue(g.ParentID,out parent))
{
parent.Groups.Add(g);
}
}
}
您可以试试这个

public interface IGroup
{
    string ID { get; set; }  
    string Name { get; set; }  
    string ParentID { get; set; }  
    List<IGroup> Groups { get; set; }
}
public class Group : IGroup
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string ParentID { get; set; }
    public List<IGroup> Groups { get; set; }
    public Group()
    {

    }
    public Group(string id, string name, List<IGroup> childs)
    {
        ID = id;
        Name = name;
        Groups = (List<IGroup>)childs.Cast<IGroup>();
    }

}


class Program
{
    static void Main(string[] args)
    {
        List<IGroup> OriginalList;
        List<IGroup> HirarchList = new List<IGroup>();

        OriginalList = new List<IGroup>() 
        { 
            new Group() { ID = "g1", ParentID = null }, 
            new Group() { ID = "g2", ParentID = "g1" }, 
            new Group() { ID = "g3", ParentID = null }, 
            new Group() { ID = "g4", ParentID = "g3" }, 
            new Group() { ID = "g5", ParentID = "g4" }, 
            new Group() { ID = "g6", ParentID = "g5" } };

        HirarchList = GetCreateList(null,  OriginalList);
    }
    public static List<IGroup> GetCreateList(string id, List<IGroup> list)
    {
        List<IGroup> temp = new List<IGroup>();
        temp = (from item in list 
               where item.ParentID == id
               select (IGroup)new Group(item.ID, item.Name,GetCreateList(item.ID, list))).ToList();

        return (List<IGroup>)temp;
    }

}
公共接口IGroup
{
字符串ID{get;set;}
字符串名称{get;set;}
字符串ParentID{get;set;}
列表组{get;set;}
}
公共类组:IGroup
{
公共字符串ID{get;set;}
公共字符串名称{get;set;}
公共字符串ParentID{get;set;}
公共列表组{get;set;}
公共组()
{
}
公共组(字符串id、字符串名称、列表子项)
{
ID=ID;
名称=名称;
Groups=(List)childs.Cast();
}
}
班级计划
{
静态void Main(字符串[]参数)
{
列表原创者;
List HirarchList=新列表();
原始列表=新列表()
{ 
新组(){ID=“g1”,ParentID=null},
新组(){ID=“g2”,ParentID=“g1”},
新组(){ID=“g3”,ParentID=null},
新组(){ID=“g4”,ParentID=“g3”
public interface IGroup
{
    string ID { get; set; }  
    string Name { get; set; }  
    string ParentID { get; set; }  
    List<IGroup> Groups { get; set; }
}
public class Group : IGroup
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string ParentID { get; set; }
    public List<IGroup> Groups { get; set; }
    public Group()
    {

    }
    public Group(string id, string name, List<IGroup> childs)
    {
        ID = id;
        Name = name;
        Groups = (List<IGroup>)childs.Cast<IGroup>();
    }

}


class Program
{
    static void Main(string[] args)
    {
        List<IGroup> OriginalList;
        List<IGroup> HirarchList = new List<IGroup>();

        OriginalList = new List<IGroup>() 
        { 
            new Group() { ID = "g1", ParentID = null }, 
            new Group() { ID = "g2", ParentID = "g1" }, 
            new Group() { ID = "g3", ParentID = null }, 
            new Group() { ID = "g4", ParentID = "g3" }, 
            new Group() { ID = "g5", ParentID = "g4" }, 
            new Group() { ID = "g6", ParentID = "g5" } };

        HirarchList = GetCreateList(null,  OriginalList);
    }
    public static List<IGroup> GetCreateList(string id, List<IGroup> list)
    {
        List<IGroup> temp = new List<IGroup>();
        temp = (from item in list 
               where item.ParentID == id
               select (IGroup)new Group(item.ID, item.Name,GetCreateList(item.ID, list))).ToList();

        return (List<IGroup>)temp;
    }

}