[英]C# List Join List And Filter From Another List
Need some help constructing proper LINQ query with join.需要一些帮助来使用连接构建正确的 LINQ 查询。
I have the following setup:我有以下设置:
public class Student
{
public string StudentName { get; set; }
public string StudentEmail { get; set; }
}
public class Enrolled
{
public Student Student { get; set; }
public string Subject { get; set; }
}
public class Dropped
{
public Student Student { get; set; }
public string Subject { get; set; }
}
// Populating the List.
// Setup the Student List
List<Student> lstStudents = new List<Student>();
var John = new Student()
{
StudentEmail = "john@stanford.edu",
StudentName = "John Wayne"
};
var Maya = new Student()
{
StudentEmail = "maya@stanford.edu",
StudentName = "Maya Agnes"
};
var Eric = new Student()
{
StudentEmail = "eric@stanford.edu",
StudentName = "Eric James"
};
var Ellen = new Student()
{
StudentEmail = "ellen@stanford.edu",
StudentName = "Ellen Page"
};
lstStudents.Add(John);
lstStudents.Add(Maya);
lstStudents.Add(Eric);
lstStudents.Add(Ellen);
// Setup the Enrolled List
List<Enrolled> lstEnrolled = new List<Enrolled>();
// John
var JohnMath = new Enrolled() { Student = John, Subject = "Math" };
var JohnScience = new Enrolled() { Student = John, Subject = "Science" };
var JohnEnglish = new Enrolled() { Student = John, Subject = "English" };
// Maya
var MayaMath = new Enrolled() { Student = Maya, Subject = "Math" };
// Eric
var EricMath = new Enrolled() { Student = Eric, Subject = "Math" };
var EricScience = new Enrolled() { Student = Eric, Subject = "Science" };
var EricSocial = new Enrolled() { Student = Eric, Subject = "Social" };
// Ellen
var EllenMath = new Enrolled() { Student = Ellen, Subject = "Math" };
var EllenScience = new Enrolled() { Student = Ellen, Subject = "Science" };
var EllenEnglish = new Enrolled() { Student = Ellen, Subject = "English" };
var EllenSocial = new Enrolled() { Student = Ellen, Subject = "Social" };
lstEnrolled.Add(JohnMath);
lstEnrolled.Add(JohnScience);
lstEnrolled.Add(JohnEnglish);
lstEnrolled.Add(MayaMath);
lstEnrolled.Add(EricMath);
lstEnrolled.Add(EricScience);
lstEnrolled.Add(EricSocial);
lstEnrolled.Add(EllenMath);
lstEnrolled.Add(EllenScience);
lstEnrolled.Add(EllenEnglish);
lstEnrolled.Add(EllenSocial);
// Setup the Dropped List
List<Dropped> lstDropped = new List<Dropped>();
// John dropped Math
var JohnDropMath = new Dropped() { Student = John, Subject = "Math" };
// Eric dropped Social
var EricDropSocial = new Dropped() { Student = Eric, Subject = "Social" };
// Ellen Dropped Math
var EllenDropMath = new Dropped() { Student = Ellen, Subject = "Math" };
lstDropped.Add(JohnDropMath);
lstDropped.Add(EricDropSocial);
lstDropped.Add(EllenDropMath);
What I am trying to achieve is get a list of all students, and the subjects they are enrolled in one line, like:我想要实现的是获取所有学生的列表,以及他们在一行中注册的科目,例如:
Student Subjects
------- ----------------------------------
John English, Science
Maya Math
Eric Math, Science
Ellen English, Science, Social
I have constructed the following so far:到目前为止,我已经构建了以下内容:
var StudentsAndCurrentSubjects = (from st in lstStudents
join en in lstEnrolled
on st.StudentName equals en.Student.StudentName
select new
{
st.StudentName,
en.Subject
})
.ToList();
But it is giving me the result per person per subject.但它给了我每个人每个主题的结果。
I hit a wall on how to exclude the dropped items from the list.我在如何从列表中排除丢弃的项目方面遇到了障碍。
I am thinking of traversing the dropped list, like:我正在考虑遍历已删除的列表,例如:
foreach(d in lstDropped)
{
// Logic to Remove it from the StudentsAndCurrentSubjects
}
But I feel that it is inefficient (especially if I have lots of rows).但我觉得它效率低下(特别是如果我有很多行)。
I also do not know how to join the subjects in one line.我也不知道如何将主题加入一行。
Looking for some help here.在这里寻求帮助。
Thanks.谢谢。
We just need to first remove dropped subjects from enrolled list.我们只需要首先从注册列表中删除删除的主题。 then group by student.然后按学生分组。 note that we have list for each student, that it has Student
and Subject
as its fields, we just select the name of first student from each (as they all the same) and join the subjects together.请注意,我们有每个学生的列表,它有Student
和Subject
作为其字段,我们只需从每个学生中选择第一个学生的姓名(因为它们都相同)并将主题连接在一起。
var result = lstEnrolled.Where(e => !lstDropped.Any(d => d.Student == e.Student && d.Subject == e.Subject)) //omit dropped courses
.GroupBy(x => x.Student) // group results by students
.Select(x => new {
Name = x.First().Student.StudentName.Split(' ').First(),
Subjects = string.Join(", ", x.Select(e => e.Subject))
}).ToArray();
for printing:用于打印:
foreach(var x in result)
Console.WriteLine($"{x.Name}\t{x.Subjects}");
You are almost there.你快到了。 The join is correct, you just need to actually apply the grouping you want:加入是正确的,你只需要实际应用你想要的分组:
var StudentsAndCurrentSubjects = (from st in lstStudents
join en in lstEnrolled
on st.StudentName equals en.Student.StudentName
select new
{
st.StudentName,
en.Subject
})
.GroupBy(s => s.StudentName, d => d.Subject)
.Select(grp => new { StudentName = grp.Key, Subjects = grp.ToList() })
.ToList();
Then you can use the projection above to display it however you want.然后你可以使用上面的投影来显示它。 Something like this maybe:可能是这样的:
foreach (var grouping in StudentsAndCurrentSubjects) {
var studentName = grouping.StudentName;
var subjects = string.Join(", ", grouping.Subjects);
Console.WriteLine($"{studentName}\t{subjects}");
}
Try a GroupJoin
by using the into
keyword.使用into
关键字尝试GroupJoin
。
var studentsAndCurrentSubjects = (
from student in lstStudents
join enrollment in lstEnrolled
on student equals enrollment.Student
into enrollments
join drop in lstDrop
on student equals drop.Student
into drops
let classes = enrollments.Select(e => e.Subject).Except(drops.Select(d => d.Subject))
select new
{
Student = student.StudentName,
Subjects = string.Join(", ", classes)
})
.ToList();
Or, you can subquery with let
.或者,您可以使用let
进行子查询。 This will have noticeably slower performance against larger lists than the other solution, but it should be fine in the database.与其他解决方案相比,这对于较大列表的性能明显较慢,但在数据库中应该没问题。
var studentsAndCurrentSubjects = (
from student in lstStudents
let enrollments = lstEnrolled.Where(x => student == x.Student).Select(x => x.Subject)
let drops = lstDrops.Where(x => student == drop.Student).Select(x => x.Subject)
let classes = enrollments.Except(drops)
select new
{
Student = student.StudentName,
Subjects = string.Join(", ", classes)
})
.ToList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.