LINQ recursive query to return hierarchical set of groups

前端 未结 3 1417
花落未央
花落未央 2020-12-09 13:08

Given a list of the following models

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

I

相关标签:
3条回答
  • 2020-12-09 13:30

    Firstly you will need an object like this, so the Team object might be:

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

    Then a 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 passes a null for parent, and will pull all the teams that have a null parent :), though I notice your teams don't have a null for parent, so not sure how you identify the top level ones currently?

    0 讨论(0)
  • 2020-12-09 13:37

    So first, your TeamGrouping is actually a bit more complex than it needs to be. All it needs is the Team object and a sequence of itself for children:

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

    Next we'll take our sequence of teams and create a node for each one. Then we'll use ToLookup to group them by their parent ID. (Your use of GroupBy is pretty darn close to this, but ToLookup will be easier.) Finally we can just set each node's children to be the lookup value for that node (note that ILookup will return an empty sequence if the key doesn't exist, so our leaves will be handled perfectly). To finish it off we can return all of the top level nodes by just looking up all nodes with a parent ID of 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];
    }
    
    0 讨论(0)
  • 2020-12-09 13:39

    Another solution for when you are using Entity Framework objects you can handle root objects (Parent == null) by removing the Team objects that have a null parent 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 讨论(0)
提交回复
热议问题