使用LINQ查找两个列表中具有相同子项的项目

huangapple go评论68阅读模式
英文:

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 AList 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&lt;Course&gt; 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&lt;Student, List&lt;Student&gt;&gt; result = listA
	.ToDictionary(
		keySelector: studentA =&gt; studentA,
		elementSelector: studentA =&gt;
			listB.Where(studentB =&gt;
				// check that they have same number of courses
				studentA.Courses.Count == studentB.Courses.Count
				// check that all courses are the same
				&amp;&amp; studentA.Courses.Select(c =&gt; c.Id).Intersect(studentB.Courses.Select(c =&gt; 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 =&gt; string.Join(&quot;,&quot;, a.Courses.Select(course =&gt; course.Id).OrderBy(g =&gt; g)),
     b =&gt; string.Join(&quot;,&quot;, b.Courses.Select(course =&gt; course.Id).OrderBy(g =&gt; g)),
    (a, bs) =&gt; (student: a, list: bs.ToList()))
  .Where(group =&gt; group.list.Count &gt; 0)
  .ToList(); // &lt;- let&#39;s have a list

For instance, for

  Course algebra = new Course() { Id = Guid.NewGuid(), Name = &quot;Algebra&quot; };
  Course geometry = new Course() { Id = Guid.NewGuid(), Name = &quot;Geometry&quot; };
  Course arithmetics = new Course() { Id = Guid.NewGuid(), Name = &quot;Arithmetics&quot; };

  List&lt;Student&gt; listA = new List&lt;Student&gt;() {
    new Student() { Id = Guid.NewGuid(), Name = &quot;John&quot;, Courses = new List&lt;Course&gt;() { algebra, geometry} },
    new Student() { Id = Guid.NewGuid(), Name = &quot;Anna&quot;, Courses = new List&lt;Course&gt;() { algebra } }
  };

  List&lt;Student&gt; listB = new List&lt;Student&gt;() {
    new Student() { Id = Guid.NewGuid(), Name = &quot;Jack&quot;, Courses = new List&lt;Course&gt;() { algebra, geometry} },
    new Student() { Id = Guid.NewGuid(), Name = &quot;Jill&quot;, Courses = new List&lt;Course&gt;() { algebra, geometry}, },
    new Student() { Id = Guid.NewGuid(), Name = &quot;Natasha&quot;, Courses = new List&lt;Course&gt;() { algebra, geometry, arithmetics} }
  };

If we run the query above and print it as

var report = result
  .Select(group =&gt; $&quot;{group.student.Name} : {string.Join(&quot;, &quot;, group.list.Select(s =&gt; s.Name))}&quot;);

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 =&gt; x.Name == &quot;John&quot;);
var studentLikeJohn = studentList.Where(x =&gt; john.Courses.IntersectBy(x.Courses.Select(y =&gt; y.Name), y =&gt; y.Name).Count() == john.Courses.Count &amp;&amp; x.Courses.Count == john.Courses.Count).ToList();

huangapple
  • 本文由 发表于 2023年3月7日 05:36:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656068.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定