转换并重新排列列表<>

时间:2014-01-27 15:25:56

标签: c# .net-4.0

我有一个培训列表,其中包括主题列表,每个主题包括用户列表如下:

internal class Training
    {
        public string Name { get; set; }
        public List<Subject> Subjects { get; set; }
    }

    internal class Subject
    {
        public string Name { get; set; }
        public List<User> Users { get; set; }
    }

    internal class User
    {
        public string UserId { get; set; }
        public string FullName { get; set; }

    }

现在我必须写另一个课程,该课程将返回不同用户列表及其所有培训和科目如下:

internal class UserData
    {
        public string UserId { get; set; }
        public string FullName { get; set; }
        public List<string> SubjectNames { get; set; }
        public List<string> TrainingNames { get; set; }
    }

从训练和科目中我只需要他们的名字。

我已经编写了读取数据库的部分并返回List<Training>现在如何将其转换为List<UserData>

实施例

输入

List<Training> trainings;
  • 培训==&gt; .NET
    • 主题==&gt; MVC
      • 用户==&gt;麦克
      • 用户==&gt;约翰
    • 主题==&gt; ASP.NET
      • 用户==&gt;麦克
      • 用户==&gt;金
  • 培训==&gt;爪哇
    • 主题==&gt; EJB
      • 用户==&gt;麦克
      • 用户==&gt;金

输出

List<UserData> usersData;
  • 的UserData ==&GT;麦克
    • 培训==&gt; .NET
    • 培训==&gt;爪哇
    • 主题==&gt; MVC
    • 主题==&gt; ASP.NET
    • 主题==&gt; EJB
  • 的UserData ==&GT;约翰
    • 培训==&gt; .NET
    • 主题==&gt; MVC
  • 的UserData ==&GT;金
    • 培训==&gt; .NET
    • 培训==&gt;爪哇
    • 主题==&gt; ASP.NET
    • 主题==&gt; EJB

希望现在更清楚了。

4 个答案:

答案 0 :(得分:2)

这应该有效:

List<UserData> userDataList = trainings
    .Select(training => 
    {
        var distUsers = training.Subjects.SelectMany(ts => ts.Users)  // flatten out all users
            .GroupBy(u => new { u.UserId, u.FullName})                // group by u.UserId and u.FullName
            .Select(grp => grp.First());                              // take simply the first
        return new { training, users = distUsers };                   // return this anonymous type
    })
    .SelectMany(x => x.users                                          // flatten out all distinct users
        .Select(u => new UserData                                     // for each create an instance of UserData  
        {
            UserId = u.UserId,
            FullName = u.FullName,
            SubjectNames = x.training.Subjects.Select(s => s.Name).ToList(), // select only the name and create a list
            TrainingNames = x.training.Name
        }))
    .ToList();  // create the final list

修改:根据您更改的要求,您的TrainingName(s)实际上是List<string>(全部更改)。我会实现一个自定义IEqualityComparer<User>,您可以将其用于DistinctGroupBy(例如):

public class UserComparer : IEqualityComparer<User>
{
    public bool Equals(User x, User y)
    {
        if (object.ReferenceEquals(x, y)) return true;
        if (x == null ||y == null) return false;
        return x.UserId == y.UserId && x.FullName == y.FullName;
    }

    public int GetHashCode(User obj)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + (obj.UserId ?? "").GetHashCode();
            hash = hash * 23 + (obj.FullName ?? "").GetHashCode();
            return hash;
        }
    }
}

然后以下查询应该有效:

var uComparer = new UserComparer();
var distinctUsers = trainings
    .SelectMany(t => t.Subjects.SelectMany(ts => ts.Users))
    .Distinct(uComparer);
List<UserData> userData = distinctUsers
    .SelectMany(u => 
    {
        var subjectsWithUser = trainings
            .SelectMany(t => t.Subjects
                .Where(ts => ts.Users
                    .Any(tsu => tsu.UserId == u.UserId && tsu.FullName == u.FullName)))
                .Select(ts => new { user = u, training = t, subject = ts });
        return subjectsWithUser;
    })
    .GroupBy(x => x.user, uComparer)
    .Select(grp => new UserData
    {
        UserId = grp.Key.UserId, FullName = grp.Key.FullName,
        TrainingNames = grp.Select(xx => xx.training.Name).Distinct().ToList(),
        SubjectNames = grp.Select(xx => xx.subject.Name).Distinct().ToList(),
    })
    .ToList();

答案 1 :(得分:0)

你可以尝试一下

var usersData = trainings
    .SelectMany(
        training => training.Subjects.Select(
            subject => new { TrainingName = training.Name, Subject = subject })
    .SelectMany(
        subject => subject.Users.Select(
            user => new { TrainingName = training.Name, SubjectName = subject.Name, User = user })
    .GroupBy(user => user.User)
    .Select(grouping => new UserData 
                {
                    UserId = grouping.Key.UserId,
                    FullName = grouping.Key.FullName,
                    TrainingName = grouping.Select(user => user.TrainingName), 
                    SubjectName = grouping.Select(user => user.SubjectName )
                });

答案 2 :(得分:0)

首先展平为Training/Subject/Users列表,然后按用户分组:

lstTraining.SelectMany(t => t.Subjects, (t, s) => new{t,s})
           .SelectMany(ts => ts.s.Users, (ts, u) => new{ts.t, ts.s, u})
           .GroupBy(tsu => tsu.u)
           .Select(g => new UserData 
                      {
                      UserId = g.Key.UserId,
                      FullName = g.Key.FullName,
                      SubjectNames = g.Select(tsu => tsu.s.Name)
                                      .Distinct()
                                      .ToList(),
                      TrainingNames = g.Select(tsu => tsu.t.Name)
                                       .Distinct()
                                       .ToList()
                     }

                   );      

答案 3 :(得分:0)

那样的东西? 假设Users.Contains(u)将正常工作,这意味着用户准确“可比”。 假设TrainingNames应该是与用户相关的培训名称的串联。 它看起来很长,因为我尽可能地缩进代码(几乎),希望它更具可读性。

            internal List<UserData> ConverToUserDataList(List<Training> TrainingList, List<Subject> AllSubjects)
    {
        List<UserData> userDataList = new List<UserData>();
        IEnumerable<Subject> usersSubjects;
        TrainingList.ForEach
        (
            training =>
                training.Subjects.ForEach
                (
                    subject =>
                        subject.Users.ForEach
                        (
                            user =>
                                {
                                    usersSubjects = AllSubjects.Where(subjectB => subjectB.Users.Contains(user));
                                    userDataList.Add
                                    (
                                        new UserData
                                        {
                                            UserId = user.UserId,
                                            FullName = user.FullName,
                                            SubjectNames = usersSubjects.Select(subjectB => subjectB.Name).ToList(),
                                            TrainingNames = string.Join(
                                                                            ",",
                                                                            TrainingList.Where(trainingB => trainingB.Subjects.Intersect(usersSubjects).Any()).Select(trainingB => trainingB.Name).ToList()
                                                                        )
                                        }
                                    );
                                }
                        )
                )
        );
        return userDataList;
    }