C# 列出联接列表并从另一个列表中筛选
需要一些帮助来构造正确的带有连接的LINQ查询 我有以下设置:C# 列出联接列表并从另一个列表中筛选,c#,linq,C#,Linq,需要一些帮助来构造正确的带有连接的LINQ查询 我有以下设置: 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 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);
到目前为止,我已经构建了以下内容:
var StudentsAndCurrentSubjects = (from st in lstStudents
join en in lstEnrolled
on st.StudentName equals en.Student.StudentName
select new
{
st.StudentName,
en.Subject
})
.ToList();
但它给了我每个人每个主题的结果
关于如何从列表中排除掉的项目,我遇到了一个难题
我正在考虑遍历删除的列表,如:
foreach(d in lstDropped)
{
// Logic to Remove it from the StudentsAndCurrentSubjects
}
但是我觉得它效率很低(特别是如果我有很多行的话)
我也不知道如何将主题连接在一行中
这里需要帮助
谢谢。我们只需要首先从注册列表中删除掉的科目。然后按学生分组。 请注意,我们有每个学生的列表,它有
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();
用于打印:
foreach(var x in result)
Console.WriteLine($"{x.Name}\t{x.Subjects}");
你就快到了。联接是正确的,您只需实际应用所需的分组:
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();
然后,您可以使用上面的投影来显示它。可能是这样的:
foreach (var grouping in StudentsAndCurrentSubjects) {
var studentName = grouping.StudentName;
var subjects = string.Join(", ", grouping.Subjects);
Console.WriteLine($"{studentName}\t{subjects}");
}
使用
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();
或者,您可以使用let
进行子查询。与其他解决方案相比,对于较大的列表,这将显著降低性能,但在数据库中应该可以
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();
很好的解决方案。2个想法:#1可以使用
Name=x.Key.StudentName
作为名称#2个没有课程的学生将不会出现在输出中,这可能是需要的。OP明确定义了他想要的输出。我在代码中添加了一个实时演示,您可以检查。
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();