0

生徒の名前とテストの点数の配列が2つあります。

各配列には個別の学生のみが含まれ(重複はありません)、とのように構成されarrStudentGroup1[0][0] = "Bob"ていarrStudentGroup1[0][1] = "98"ます。

2つの配列が与えられた場合、との両方にIntersect存在する学生の3番目の配列を作成するために使用することが可能ですか? arrStudentGroup1arrStudentGroup2

3番目の配列に名前とテストスコアを付けてほしい。どうすればよいですか?

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>、各配列の最初の要素を比較するを実装する必要があります。

関連するテストスコアが必要な場合は、2つの配列を結合します。

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

さて、あなたはこのような何かをすることができます、

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 に答える
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]});

次に交差点を取得します。同じ学生名が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});

そして、あなたが本当に、本当にすべてを同じ文字列[] []形式にしたいのなら:

var interArrays = interArray.ToArray();

または、1行の不思議(ほとんどの場合、読みやすさは劣りますが、同じメソッドで他のことが起こっている場合は、1行にクエリを配置すると便利な場合があります):

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[]>編集:または、次のように定義します。

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 に答える