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