英文:
Finding items with exact subitems in two lists using LINQ
问题
public class Student
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<Course> Courses { get; set; } = new();
}
public class Course
{
public Guid Id { get; set; }
public string Name { get; set; }
}
我需要找到来自List A
和List B
的学生,他们选修完全相同的课程。
例如,我有List A
中的John,他选修了英语、代数和化学。我想找到List B
中所有选修英语、代数和化学的学生。如果List B
中的学生,比如James,选修了这三门课程,但还选修了其他课程,那就不符合条件。所以,他们选修的课程必须完全匹配。
我将对List A
中的每个学生都执行此操作。
我不确定如何使用LINQ
处理课程的精确匹配。我考虑过使用Contains
,但我需要确保来自List A
的学生所选的所有课程都与来自List B
的学生所选的课程完全匹配。
我可以尝试使用嵌套的foreach
,但我认为LINQ
也可以处理,并且可能性能更好。
我希望能够得到一些建议。
英文:
I have two lists of students who take courses in a school. My classes look like this:
public class Student
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<Course> Courses { get; set; } = new();
}
And the Course
looks like this:
public class Course
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I need to find students from both List A
and List B
who take the exact same courses.
Say, I have John in List A
who takes English, Algebra and Chemistry. I want to find all students in List B
who also take English, Algebra and Chemistry. If a student, say James, in List B
takes these three courses but an additional course, it would NOT qualify. So the courses they take must match exactly.
And I'll be doing this for every student in List A
.
I'm not sure how to handle the exact match of courses using LINQ
. I thought about using Contains
but I need to make sure ALL the courses student from List A
is taking match the ones student from List B
is taking.
I'm open to using nested foreach
but I think LINQ
could handle it too and possibly perform better.
I'd appreciate some pointers on this.
答案1
得分: 3
请尝试以下代码:
Dictionary<Student, List<Student>> result = listA
.ToDictionary(
keySelector: studentA => studentA,
elementSelector: studentA =>
listB.Where(studentB =>
// 检查它们是否拥有相同数量的课程
studentA.Courses.Count == studentB.Courses.Count
// 检查所有课程是否相同
&& studentA.Courses.Select(c => c.Id).Intersect(studentB.Courses.Select(c => c.Id)).Count() == studentA.Courses.Count)
.ToList());
结果是一个字典,其中键是来自列表 A 的学生,值是来自列表 B 与之匹配课程的学生。
基本上,它检查课程数量是否相同,还检查课程之间的交集是否具有相同的数量,因此课程完全相同。
英文:
Try this:
Dictionary<Student, List<Student>> result = listA
.ToDictionary(
keySelector: studentA => studentA,
elementSelector: studentA =>
listB.Where(studentB =>
// check that they have same number of courses
studentA.Courses.Count == studentB.Courses.Count
// check that all courses are the same
&& studentA.Courses.Select(c => c.Id).Intersect(studentB.Courses.Select(c => c.Id)).Count() == studentA.Courses.Count)
.ToList());
The result is a dictionary where the key is a student from list A and values are students with matching courses from list B.
It's basically checking that the count of courses is the same and also that the intersect between courses has the same count, therefore the courses are all exactly the same.
答案2
得分: 2
看起来你正在寻找GroupJoin:对于listA
中的每个学生,我们希望从listB
中获取具有相同课程的组:
var result = listA
.GroupJoin(listB,
a => string.Join(",", a.Courses.Select(course => course.Id).OrderBy(g => g)),
b => string.Join(",", b.Courses.Select(course => course.Id).OrderBy(g => g)),
(a, bs) => (student: a, list: bs.ToList()))
.Where(group => group.list.Count > 0)
.ToList(); // <- 让我们得到一个列表
例如,对于以下数据:
Course algebra = new Course() { Id = Guid.NewGuid(), Name = "Algebra" };
Course geometry = new Course() { Id = Guid.NewGuid(), Name = "Geometry" };
Course arithmetics = new Course() { Id = Guid.NewGuid(), Name = "Arithmetics" };
List<Student> listA = new List<Student>() {
new Student() { Id = Guid.NewGuid(), Name = "John", Courses = new List<Course>() { algebra, geometry} },
new Student() { Id = Guid.NewGuid(), Name = "Anna", Courses = new List<Course>() { algebra } }
};
List<Student> listB = new List<Student>() {
new Student() { Id = Guid.NewGuid(), Name = "Jack", Courses = new List<Course>() { algebra, geometry} },
new Student() { Id = Guid.NewGuid(), Name = "Jill", Courses = new List<Course>() { algebra, geometry}, },
new Student() { Id = Guid.NewGuid(), Name = "Natasha", Courses = new List<Course>() { algebra, geometry, arithmetics} }
};
如果我们运行上述查询并将其打印为:
var report = result
.Select(group => $"{group.student.Name} : {string.Join(", ", group.list.Select(s => s.Name))}");
Console.Write(string.Join(Environment.NewLine, report));
我们将获得以下结果:
John : Jack, Jill
请参考fiddle。
英文:
It seems that you are looking for GroupJoin: for each student from listA
we want to get a group from listB
with the same courses:
var result = listA
.GroupJoin(listB,
a => string.Join(",", a.Courses.Select(course => course.Id).OrderBy(g => g)),
b => string.Join(",", b.Courses.Select(course => course.Id).OrderBy(g => g)),
(a, bs) => (student: a, list: bs.ToList()))
.Where(group => group.list.Count > 0)
.ToList(); // <- let's have a list
For instance, for
Course algebra = new Course() { Id = Guid.NewGuid(), Name = "Algebra" };
Course geometry = new Course() { Id = Guid.NewGuid(), Name = "Geometry" };
Course arithmetics = new Course() { Id = Guid.NewGuid(), Name = "Arithmetics" };
List<Student> listA = new List<Student>() {
new Student() { Id = Guid.NewGuid(), Name = "John", Courses = new List<Course>() { algebra, geometry} },
new Student() { Id = Guid.NewGuid(), Name = "Anna", Courses = new List<Course>() { algebra } }
};
List<Student> listB = new List<Student>() {
new Student() { Id = Guid.NewGuid(), Name = "Jack", Courses = new List<Course>() { algebra, geometry} },
new Student() { Id = Guid.NewGuid(), Name = "Jill", Courses = new List<Course>() { algebra, geometry}, },
new Student() { Id = Guid.NewGuid(), Name = "Natasha", Courses = new List<Course>() { algebra, geometry, arithmetics} }
};
If we run the query above and print it as
var report = result
.Select(group => $"{group.student.Name} : {string.Join(", ", group.list.Select(s => s.Name))}");
Console.Write(string.Join(Environment.NewLine, report));
We'll get
John : Jack, Jill
Please, fiddle
答案3
得分: 1
你可以尝试这个:
// studentList 是 Student 对象的列表
var john = studentList.FirstOrDefault(x => x.Name == "John");
var studentLikeJohn = studentList.Where(x =>
john.Courses.Intersect(x.Courses.Select(y => y.Name)).Count() == john.Courses.Count &&
x.Courses.Count == john.Courses.Count).ToList();
英文:
You can try this;
//studentList is the List of Student object
var john = studentList.FirstOrDefault(x => x.Name == "John");
var studentLikeJohn = studentList.Where(x => john.Courses.IntersectBy(x.Courses.Select(y => y.Name), y => y.Name).Count() == john.Courses.Count && x.Courses.Count == john.Courses.Count).ToList();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论