2

我有一个 Person 对象,它具有以下属性

public class Person
{
   public string FirstName;
   public string LastName;
   public string TeamName;
   public Person Manager;
   public IEnumerable<Person> DirectReports;
}

因此,鉴于我可以通过递归循环每个人的直接报告及其直接报告等来创建人的层次结构,如下所示:

foreach (Person direct in person.DirectReports)
{
       foreach (Person subDirect in direct.DirectReports)
       {
            etc . . .
       }
}

从这些数据中,我现在正在尝试转换以生成团队的层次结构,所以我有这样的东西:

 public class Team
 {
    public string TeamName;
    public IEnumerable<Team> SubTeams;
    public IEnumerable<Person> PeopleInTeam;
}

请注意,如果一个人的 directReports 可能具有或可能不具有相同的 TeamName,则人员层次结构中的人员级别数不一定与团队层次结构中的级别数相同

例如:

| 人| 家长| 队名 |  
| 比尔 | "" | 管理 |  
| 乔 | 比尔 | 管理 |  
| 斯科特 | 比尔 | 营销 |  
| 吉姆 | 比尔 | 技术 |   
| 马克 | 斯科特 | 营销 |
| 鲍勃 | 乔 | 营销 |

所以在转换之后,我会有一个名为“管理”的团队,里面有 2 个人。SubTeams 数组中有 2 项(一项用于营销,一项用于技术)。每个团队在 SubTeams 数组中都没有条目

有效地采用这种人员层次结构并将其转换为团队层次结构的最佳方法是什么?我已经列出了下面的代码,但它似乎失败了。现在,我正在遍历每个人和他们的直接下属,并创建一个团队字典,并一次将每个人添加到一个团队中,但这似乎很慢。这是一个例子..

 Dictionary<string, Team> teams = new Dictionary<string, Team>();

 foreach (Person direct in person.DirectReports)
 {
       if (teams.ContainsKey(direct.TeamName)
       {
              var team = teams[direct.TeamName];
              team.People.Add(direct);
       }
       else
       {
            var team = new Team(){TeamName = direct.TeamName};
            team.People.Add(direct);
            teams[direct.TeamName] = team;
       }
       foreach (Person subDirect in direct.DirectReports)
       {
            etc . . .
       }
}
4

2 回答 2

2

这是一个可以用作框架的基本解决方案。

这并不理想:尤其是,Dictionary<string, string>它不是一个好的数据结构,因为无论如何我们最终都会遍历所有值。Dictionary<string, List<string>>构建一个从部门映射到其子部门名称的东西会更有用。

但它应该给你一个工作的基础。

void Main()
{
    var bill = new Person { FirstName = "Bill", TeamName = "Management" };
    var joe = new Person { FirstName = "Joe", Manager = bill, TeamName = "Management" };
    var scott = new Person { FirstName = "Scott", Manager = bill, TeamName = "Marketing" };
    var jim = new Person { FirstName = "Jim", Manager = bill, TeamName = "Technology" };
    var mark = new Person { FirstName = "Mark", Manager = scott, TeamName = "Marketing" };
    var bob = new Person { FirstName = "Bob", Manager = joe, TeamName = "Marketing" };
    var ted = new Person { FirstName = "Ted", Manager = jim, TeamName = "IT Support" };

    var people = new[] { bill, joe, scott, jim, mark, bob, ted };

    var teamParents = people.Select (p => new { Team = p.TeamName, ParentTeam = p.Manager == null ? null : p.Manager.TeamName });

    // don't let a team be its own parent
    teamParents = teamParents.Where (p => !p.Team.Equals(p.ParentTeam));

    // make sure they're all unique
    teamParents = teamParents.Distinct();

    // put it in a dictionary
    var teamHierarchy = teamParents.ToDictionary (p => p.Team, q => q.ParentTeam);

    foreach (string root in teamHierarchy.Where (h => h.Value == null).Select (h => h.Key))
    {    
        PrintSubteams(teamHierarchy, 0, root);
    }    
}

private void PrintSubteams(Dictionary<string, string> hierarchy, int level, string root)
{
    for (int i = 0; i < level; i++)
    {
        Console.Write("    ");
    }

    Console.WriteLine(root);

    foreach (string child in hierarchy.Where (h => h.Value == root).Select(h => h.Key))
    {
        PrintSubteams(hierarchy, level + 1, child);
    }
}

public class Person
{
    public string FirstName;
    public string LastName;
    public string TeamName;
    public Person Manager;
    public IEnumerable<Person> DirectReports;
}

输出如下:

管理
    营销
    技术
        IT支持

(我添加了 IT 支持团队以使其更有趣。)

于 2013-09-29T09:45:35.840 回答
0

如果您只有树顶部的人员列表,那么我们可以试试这个:

public void ConstructTeams(IEnumerable<Person> topPeople,
    Dictionary<string, Team> teamsByName)
{
    foreach (Person person in topPeople)
    {
        // Add person to their team. Create one if it doesn't exist
        Team matchingTeam;
        if (teamsByName.TryGetValue(person.TeamName, out matchingTeam))
        {
            matchingTeam.PeopleInTeam.Add(person);
        }
        else
        {
            // Create a new team and update its parent team
            matchingTeam = new Team
            {
                TeamName = direct.TeamName
                PeopleInTeam = new List<Person>()
            };
            matchingTeam.PeopleInTeam.Add(person);
            teamsByName.Add(matchingTeam.TeamName, matchingTeam);

            // The manager's team should already exist because we traversing the
            // Person tree/forest from the roots to the leaves
            if (person.Manager != null)
            {
                teamsByName[person.Manager.TeamName].SubTeams.Add(matchingTeam);
            }
        }

        // Recursively fill in the direct reports
        ConstructTeams(person.DirectReports, teamsByName);
    }
}

如果您有一个所有人的平面列表,这是一个解决方案。

public IEnumerable<Team> ConstructTeams(IEnumerable<Person> allPeople)
{
    var teams = allPeople.GroupBy(person => person.TeamName)
        .Select(grouping => new Team
        {
            TeamName = grouping.Key,
            // I think this works, but IGroupings are weird and I don't
            // have a compiler with me
            PeopleInTeam = grouping.ToList()
        });

    // Set SubTeams
    // Group the teams by parent team. We assumed that
    // no team has two parent teams
    var teamsGroupedByParentTeam = teams
        .GroupBy(team => team.PeopleInTeam.First().TeamName);

    foreach (var groupOfTeams in teamsGroupedByParentTeam)
    {
        var parentTeam = teams.Single(team => team.TeamName == teamsGroupedByParentTeam.TeamName);
        parentTeam.SubTeams = groupOfTeams.ToList();
    }

    return teams;
}
于 2013-09-29T05:28:56.607 回答