我有一个培训列表,其中包括主题列表,每个主题包括用户列表如下:
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;
输出
List<UserData> usersData;
希望现在更清楚了。
答案 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>
,您可以将其用于Distinct
和GroupBy
(例如):
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;
}