0

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

每个数组只包含不同的学生(没有重复),并且结构为arrStudentGroup1[0][0] = "Bob"arrStudentGroup1[0][1] = "98"

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

我希望第三个数组有他们的名字和考试成绩。我该怎么做呢?

4

3 回答 3

2

如果您想要两个组中的学生姓名而不是相关的考试成绩,只需在 name 数组元素上相交:

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

var studentsInBoth = students1.Intersect(students2);

如果您还想要相关的测试分数,您需要实现一个IEqualityComparer<T>比较每个数组的第一个元素的方法。

如果您想要相关的考试成绩,请加入两个数组:

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);
}
于 2012-09-07T14:38:44.450 回答
0

首先将数组压缩(在一般意义上,而不是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 zipped1 = arrStudentGroup1.Select(student => new {Name = student[0], Score = student[1]});
var zipped2 = arrStudentGroup2.Select(student => new {Name = student[0], Score = student[1]});

现在得到路口。请注意,如果同一学生姓名在一个但分数不同,则不会算作交叉点。这也可以处理,但我将您的问题解释为不想要这种情况。如果我读错了,请告诉我:

var inter = zipped1.Intersect(zipped2);

现在,无论如何,您都可以理想地使用它,甚至可以使用new {Name = student[0], Score = int.Parse(student[1])}上面的数字而不是字符串(在大多数情况下更有用),坦率地说,这比处理数组数组更好,而且类型更安全。不过,如果您真的希望它采用相同的格式 string[] 格式:

var interArray = inter.Select(st => new string[]{st.Name, st.Score});

如果你真的,真的希望整个事情都采用相同的 string[][] 格式:

var interArrays = interArray.ToArray();

或者对于单行奇迹(主要是可读性较差,但如果在同一方法中还有其他事情发生,有时最好将查询放在一行上):

var interArrays = arrStudentGroup1
  .Select(student => new {Name = student[0], Score = student[1]})
  .Intersect(
    arrStudentGroup2
    .Select(student => new {Name = student[0], Score = student[1]})
  ).Select(st => new string[]{st.Name, st.Score}).ToArray()

输出:

{"Bob", "98"},{"Dariah", "99"}

编辑:或者,定义一个IEqualityComparer<string[]>like:

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);
  }
}

然后直接使用它:

var intersection = arrStudentGroup1.Intersect(arrStudentGroup2, new StudentComparer());

给出相同的输出。真的更简单,但我看到数组被用作对象时的直觉是尽快将它变成一个真实的对象,而且真的,这不是一个糟糕的直觉 - 它也可以让其他事情变得更容易。

于 2012-09-07T14:57:03.410 回答
0

嗯,你可以做这样的事情,

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];
}
于 2012-09-07T14:32:17.167 回答