【问题标题】:List<Object> to hierarchyList<Object> 到层次结构
【发布时间】:2016-10-19 07:47:41
【问题描述】:

我有一个List&lt;Data&gt;,其中有数据

public class Data
{
  public string SchoolId {get; set;}
  public string SchoolName {get; set;}
  public string TeacherId {get; set;}
  public string TeacherName {get; set;}
}

列表是扁平的:

SchoolId    SchoolName     TeacherId      TeacherName
1           X              1              Mr X
1           X              2              Mrs Y
2           Y              3              Mr Z
2           Y              1              Mr X

所以基本上一个老师可以属于很多学校。

如何将上面的平面列表转换为List&lt;School&gt;

public class School
{
     public School()
     {
          this.Teachers  = new List<Teacher>();
     }
     public string SchoolId { get; set; }
     public string SchoolName { get; set; }
     public List<Teacher> Teachers {get; set;}
}  


public class Teacher
{
    public string TeacherId { get; set; }
    public string TeacherName { get; set; }
} 

【问题讨论】:

    标签: c# linq hierarchy hierarchical-data


    【解决方案1】:

    如果是 Linq to objects,则使用此代码

    var result = list.GroupBy(x=>new {x.SchoolId, x.SchoolName})
    .Select(x=>
    {
        var s = new School();
        s.SchoolId = x.Key.SchoolId;
        s.SchoolName = x.Key.SchoolName;
        s.Teachers.AddRange(x.Select(
            y => new Teacher
            {
                TeacherId = y.TeacherId,
                TeacherName = y.TeacherName
            }
        ));
    
        return s;
    });
    

    请注意,即使在具有相同IdTeacher 中,上述代码也会导致重复的Teacher 实例。

    【讨论】:

    • s.Teachers 可能为空
    • @dotctor 它不应该用于新对象,因为它是在 School 构造函数中初始化的。
    • 你是对的。看School的构造函数就行了。
    【解决方案2】:

    这种方法的顺序是 O(n^2) 并且不共享教师实例。

    var schools = data
        .GroupBy(x => x.SchoolId)
        .Select(group => new School()
        {
            SchoolId = group.Key,
            SchoolName = group.First().SchoolName,
            Teachers = data.Where(x => x.SchoolId == group.Key)
                .Select(x => new Teacher()
                {
                    TeacherId = x.TeacherId,
                    TeacherName = x.TeacherName
                })
                .ToList()
        })
        .ToList();
    

    如果你想分享老师的实例,那么你可以使用这个

    var teachersById = data
        .GroupBy(x => x.TeacherId)
        .Select(group => new Teacher()
        {
            TeacherId = group.Key,
            TeacherName = group.First().TeacherName
        })
        .ToDictionary(x => x.TeacherId);
    
    var schools = data
        .GroupBy(x => x.SchoolId)
        .Select(group => new School()
        {
            SchoolId = group.Key,
            SchoolName = group.First().SchoolName,
            Teachers = teachersById 
                .Where(kv => data
                    .Where(x => x.SchoolId == group.Key)
                    .Select(x => x.TeacherId)
                    .Contains(kv.Key)
                )
                .Select(x => x.Value)
                .ToList()
        })
        .ToList();
    

    【讨论】:

    • 第二个不应该是简单的Teachers = group.Select(x =&gt; teachersById[x.TeacherId]).ToList()(真正利用字典)
    【解决方案3】:
    List<Data> dataList = new List<Data>();
    
    IEnumerable<School> schools = from d in dataList
                                  group d by new { SchoolId = d.SchoolId, SchoolName = d.SchoolName } into groupSchool
                                  select new School { SchoolId = groupSchool.Key.SchoolId, SchoolName = groupSchool.Key.SchoolName, Teachers =new List<Teacher>(groupSchool.Select(x => new Teacher { TeacherId = x.TeacherId, TeacherName = x.TeacherName })) };
    

    【讨论】:

      【解决方案4】:

      item.SchoolId注意:它是伪代码(对于简短的代码,我使用带参数的构造函数而不是使用属性)

      List<Data> data = //....;
      Dictionary<string, Teacher> teachers = new Dictionary<string, Teacher>();
      Dictionary<string, School> schools = new Dictionary<string, School>();
      foreach (var item in data)
      {
         if (item.TeacherId not in teachers)
            teachers.add(item.TeacherId, new Teacher(item.TeacherId, item.TeacherName));
      }
      foreach (var item in data)
      {
         if (item.SchoolId not in schools)
            schools.add(item.SchoolId , item.SchoolName, new School(item.SchoolId , teachers[item.SchoolId]));
      }
      List<School> gen_schools =     // get values from schools;
      

      附:实际上,您使用了错误的数据库表示形式(您应该将学校的教师分成两个不同的表)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-17
        相关资源
        最近更新 更多