是否可以在C#中的复杂数组上使用Intersect?

是否可以在C#中的复杂数组上使用Intersect?,c#,arrays,linq,C#,Arrays,Linq,我有两组学生姓名和考试成绩 每个数组仅包含不同的学生(无重复项),其结构应确保arrStudentGroup1[0][0]=“Bob”和arrStudentGroup1[0][1]=“98” 给定两个数组,是否可以使用Intersect创建第三个学生数组,该学生数组存在于arrStudentGroup1和arrStudentGroup2中 我希望第三个数组有它们的名字和测试分数。我该怎么做呢?嗯,你可以这样做 var studentsInGroup1 = arrStudentGroup1.Sel

我有两组学生姓名和考试成绩

每个数组仅包含不同的学生(无重复项),其结构应确保
arrStudentGroup1[0][0]=“Bob”
arrStudentGroup1[0][1]=“98”

给定两个数组,是否可以使用
Intersect
创建第三个学生数组,该学生数组存在于
arrStudentGroup1
arrStudentGroup2


我希望第三个数组有它们的名字和测试分数。我该怎么做呢?

嗯,你可以这样做

var studentsInGroup1 = arrStudentGroup1.Select(s => new 
                { 
                    Name = s[0],
                    Score = s[1]
                });

var studentsInGroup2 = arrStudentGroup2.Select(s => new 
                { 
                    Name = s[0],
                    Score = s[1]
                });

var studentsInBothGroups = studentsInGroup1.Join(
        studentsInGroup2,
        s => s.Name,
        s => s.Name,
        (one, two) => new 
             { 
                 Name = one.Name, 
                 Scores = new[] { one.Score, two.Score }
             });
这应该给你一个方便的匿名类型,你可以像这样访问

foreach(var student in studentsInBothGroups)
{
   var Name = student.Name;
   var Group1Score = student.Scores[0];
   var Group2Score = student.Scores[1];
}
如果只需要两个组中的学生姓名,而不需要关联的考试分数,只需在名称数组元素上相交即可:

var students1 = arrStudentGroup1.Select(group => group[0]);
var students2 = arrStudentGroup2.Select(group => group[0]);

var studentsInBoth = students1.Intersect(students2);
如果还需要关联的测试分数,则需要实现一个比较每个数组的第一个元素的

如果需要关联的测试分数,请加入两个数组:

var intersection = from s1 in arrStudentGroup1
      join s2 in arrStudentGroup2 on s1[0] equals s2[0]
      select new {Name = s1[0], Score1 = s1[1], Score2 = s2[1]}

foreach (var item in intersection)
{
    Console.Writeline("{0}: s1={1}, s2={2}", Name, Score1, Score2);
}
第一个zip(在一般意义上,而不是
zip
方法)将数组放入一个结构中,该结构将学生按分数分组:

鉴于:

string[][] arrStudentGroup1 = new string[][]{new string[]{"Bob","98"}, new string[]{"Alice","98"}, new string[]{"Charles","78"}, new string[]{"Dariah","99"}};
string[][] arrStudentGroup2 = new string[][]{new string[]{"Bob","98"}, new string[]{"Fiona","98"}, new string[]{"Eve","78"}, new string[]{"Dariah","99"}};
然后:

现在到十字路口。请注意,如果同一个学生的名字在一个项目中,但分数不同,那么它将而不是算作一个交叉点。这也是可以解决的,但我把你的问题解释为不想要那个案子。如果我看错了,请告诉我:

var inter = zipped1.Intersect(zipped2);
现在,不管怎样,您都可以理想地使用它,甚至可以使用上面的
new{Name=student[0],Score=int.Parse(student[1])}
,使用一个数字而不是字符串(在大多数情况下更有用),坦率地说,这比处理数组更好,而且类型更安全。但是,如果您确实希望它采用相同的格式字符串[]格式:

var interArray = inter.Select(st => new string[]{st.Name, st.Score});
var interArrays = interArray.ToArray();
如果您真的非常希望整个内容采用相同的字符串[][]格式:

var interArray = inter.Select(st => new string[]{st.Name, st.Score});
var interArrays = interArray.ToArray();
或者对于单行奇迹(大多数情况下可读性较差,但有时如果在同一方法中有其他事情发生,则最好将查询放在一行上):

输出:

{"Bob", "98"},{"Dariah", "99"}
编辑:或者,定义一个
IEqualityComparer
类似:

public class StudentComparer : IEqualityComparer<string[]>
{
  public bool Equals(string[] x, string[] y)
  {
    if(ReferenceEquals(x, y))
      return true;
    if(x == null || y == null)
      return false;
    return x.SequenceEqual(y);
  }
  public int GetHashCode(string[] arr)
  {
    return arr == null ? 0 : arr.Select(s => s == null ? 0 : s.GetHashCode()).Aggregate((x, y) => x ^ y);
  }
}

给出相同的输出。其实更简单,但我看到数组被用作对象时的本能是尽快将其转换为真实对象,而且这不是一种坏的本能——它还可以让其他事情变得更简单。

是交叉点名称还是名称和测试分数?我想交叉学生姓名,谢谢。你确定那里的
SelectMany
吗?在
string[][]
上,然后
SelectMany
将对每个字符串调用
Func
。您希望
选择
对每个
字符串[]
调用
Func
。斯坦利,谢谢。我理解并喜欢你们的两种解决方案。我刚刚了解到,对于任何一个名单上的学生来说,两个名单上的考试分数都是一样的。
var intersection = arrStudentGroup1.Intersect(arrStudentGroup2, new StudentComparer());