2013-11-15 81 views
6

的考慮下列型號列表LINQ遞歸查詢返回分層組集合

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

我想寫一個遞歸LINQ查詢,這將使我來檢索層次結構,看起來像這樣

Team 
    ChildTeams 
Team 
    Team 
     ChildTeams 

我已經嘗試了很多方法,並看到很多類似的問題,但沒有一個專門幫助我解決問題。我試過的最新嘗試沿着這些線路去:

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}); 
} 

我會強隊之列傳遞到第一ToGrouping(IEnumerable<Team>),然後返回後續羣體納入ToGrouping(IEnumerable<TeamGrouping>)但這是生產不正確的結果。

任何人有任何建議或想法?

+0

因此,您從一個平坦的團隊集合開始,並且您想創建一棵樹?我認爲你在這裏需要的不僅僅是LINQ(儘管我會非常感興趣的證明是錯誤的)。當您迭代您的團隊時,您需要構建一棵樹,而不是IGrouping的集合。 –

+0

對不起,是的,應該提到它是一個平坦的團隊名單。 – ChrisO

回答

4

所以首先,你的TeamGrouping實際上比它需要更復雜一點。它所需要的是Team對象,本身對兒童的順序:

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

下一步,我們將利用我們團隊的序列,併爲每一個節點。然後我們將使用ToLookup通過他們的父母ID對他們進行分組。 (您使用的GroupBy與此非常相近,但ToLookup會更容易。)最後,我們可以將每個節點的子節點設置爲該節點的查找值(請注意,如果密鑰沒有,則ILookup將返回空序列存在,所以我們的葉子將完美處理)。要完成它,我們可以通過查找所有父節點ID爲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]; 
} 
1

首先,你需要這樣的一個對象,所以球隊的對象可能是:

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

然後遞歸函數

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 ; 
    } 

第一個呼叫通行證父null,並會拉所有擁有空父母的球隊:),但我注意到你的球隊對於父母沒有空值,所以不確定你目前如何識別最高級別的球隊?

+0

這個效果很好,我沒有得到的一件事就是爲什麼你要創建新的Team對象,你會在任何地方都得到null屬性,你爲什麼不傳遞'team'對象? – Martin