LINQ recursive query to return a hierarchical set of groups

Given the list of the following models

public class Team { public int TeamId { get; set; } public int ParentTeamId { get; set; } } 

I am trying to write a recursive linq query that will allow me to get a hierarchy that looks like this:

 Team ChildTeams Team Team ChildTeams 

I tried many approaches and saw many similar questions, but none of them helped me solve the problem. The last attempt I tried went as follows:

 private class TeamGrouping { public int? ParentTeamId { get; set; } public IEnumerable<Team> ChildTeams { get; set; } public IEnumerable<TeamGrouping> Grouping { get; set; } } private IEnumerable<TeamGrouping> ToGrouping(IEnumerable<Team> teams) { return teams.GroupBy(t => t.ParentTeamId, (parentTeam, childTeams) => new TeamGrouping {ParentTeamId = parentTeam, ChildTeams = childTeams}); } private IEnumerable<TeamGrouping> ToGrouping(IEnumerable<TeamGrouping> teams) { return teams.GroupBy(t => t.ParentTeamId, (parentTeam, childTeams) => new TeamGrouping{ParentTeamId = parentTeam, Grouping = childTeams}); } 

I passed the list of commands to the first ToGrouping(IEnumerable<Team>) , and then the subsequent returned groups to ToGrouping(IEnumerable<TeamGrouping>) , but this leads to incorrect results.

Anyone have any tips or ideas?

+6
source share
3 answers

So your TeamGrouping is actually a little more complicated than necessary. All he needs is a Team object and its sequence for children:

 public class TeamNode { public Team Value { get; set; } public IEnumerable<TeamNode> Children { get; set; } } 

Next we take our sequence of commands and create a node for each of them. Then we will use ToLookup to group them by their parent id. (Your use of GroupBy pretty close to this, but ToLookup will be easier.) Finally, we can simply set the search value for each node for this node (note that ILookup will return an empty sequence if the key does not exist, so our leaves will be handled perfectly). To complete this, we can return all the top-level nodes by simply looking at all the nodes with the parent identifier null .

 public static IEnumerable<TeamNode> CreateTree(IEnumerable<Team> allTeams) { var allNodes = allTeams.Select(team => new TeamNode() { Value = team }) .ToList(); var lookup = allNodes.ToLookup(team => team.Value.ParentTeamId); foreach (var node in allNodes) node.Children = lookup[node.Value.TeamId]; return lookup[null]; } 
+4
source

First, you will need such an object, so the Team object can be:

 public class Team { public ParentId {get;set;} public IEnumerable<Team> ChildTeams{get;set;} } 

Then the recursive function

 private IEnumerable<Team> BuildTeams(IEnumerable<Team> allTeams, int? parentId) { var teamTree = new List<Team>(); var childTeams = allTeams.Where(o => o.ParentId == parentId).ToList(); foreach (var team in childTeams) { var t = new Team(); var children = BuildTeams(allTeams, team.TeamID); t.ChildTeams = children; teamTree.Add(t); } return teamTree ; } 

The first call goes through null for the parent and pulls out all the commands with the zero parent :), although I noticed that your commands do not have a zero value for the parent, so I'm not sure how you determine the top one at the moment?

0
source

Another solution, when you use Entity Framework objects, you can handle root objects (Parent == null) by deleting Team objects that have a parent element of zero on the first call.

 public class Team { int TeamID { get; set; } Team Parent; { get; set; } } public class TeamNode { public Team Node { get; set; } public IEnumerable<TeamNode> Children { get; set; } } private List<Team> BuildTeams(List<Team> allTeams, int? parentId) { List<TeamNodes> teamTree = new List<Team>(); List<Team> childTeams; if (parentId == null) { childTeams = allTeams.Where(o => o.Parent == null).ToList(); allTeams.RemoveAll(t => t.Parent == null); } else { childTeams = allTeams.Where(o => o.Parent.ID == parentId).ToList(); } foreach (Team team in childTeams) { TeamNode teamNode = new Team(); teamnode.Node = team; List<TeamNode> children = BuildTeams(allTeams, team.TeamID); teamNode.ChildTeams = children; teamTree.Add(t); } return teamTree ; } 
0
source

Source: https://habr.com/ru/post/958148/


All Articles