0

「Aの学生」のリストと「Bの学生」のリストがあるとします。次に、両方のリストを「学生」と呼ばれるより一般的なリストに追加します。次に、誰かが「AStudents」の重複リストを一般的な「students」リストに追加して私たちの生活を複雑にすることにしました。「A学生」の重複リストの1つを削除する最も効率的な方法は何ですか?2つのカスタムクラスが関係していることに注意してください。

コード内の一般的な学生リストはlstStudentsと呼ばれます。これは、重複を削除したいリストです。

(私はより良い例を考え出そうとしましたが、これは私が今できる最善のことです。)

LINQを使用する必要はありませんが、使用できます。MoreLinqも利用できます。

これが私のクラスです:

public class Student
{
    public Student(string _name, int _age, Exam _lastExam)
    {
        name = _name;
        age = _age;
        lastExam = _lastExam;
    }

    public string name { get; set; }
    public int age { get; set; }
    public Exam lastExam { get; set; }
}

public class Exam
{
    public Exam(int _correct, int _possible)
    {
        correct = _correct;
        possible = _possible;
    }

    public int correct { get; set; }
    public int possible { get; set; }
}

そして、これが混乱を作成するためのコードです:

List<List<Student>> lstStudents = new List<List<Student>>();
List<Student> lstAStudents = new List<Student>();
List<Student> lstDuplicateAStudents = new List<Student>();
List<Student> lstBStudents = new List<Student>();

// Create a list of some A students
lstAStudents.Add(new Student("Alex", 14, new Exam(98,100)));
lstAStudents.Add(new Student("Kim", 13, new Exam(96, 100)));
lstAStudents.Add(new Student("Brian", 14, new Exam(92, 100)));
lstStudents.Add(lstAStudents);

// Create a duplicate list of A students
lstDuplicateAStudents.Add(new Student("Alex", 14, new Exam(98, 100)));
lstDuplicateAStudents.Add(new Student("Kim", 13, new Exam(96, 100)));
lstDuplicateAStudents.Add(new Student("Brian", 14, new Exam(92, 100)));
lstStudents.Add(lstDuplicateAStudents);

// Create a list of some B students
lstBStudents.Add(new Student("John", 13, new Exam(88, 100)));
lstBStudents.Add(new Student("Jenny", 13, new Exam(80, 100)));
lstBStudents.Add(new Student("Jamie", 15, new Exam(81, 100)));
lstStudents.Add(lstBStudents);
4

2 に答える 2

4

おそらくあなたはユニークなリストを蓄積するセットを保持することができます:

var set = new HashSet<List<Student>>(new CustomComparer());
foreach (List<List<Student>> list in source)
{
  if (set.Contains(list))
    continue;
  set.Add(list)
}


public class CustomComparer : IEqualityComparer<List<Student>>
{
   public bool Equals(List<Student> one, List<Student> two)
   {
     if (one.Count != two.Count) return false;

     // simplest possible code to compare two lists
     // warning: runs in O(N*logN) for each compare
     return one.OrderBy(s=>s).SequenceEqual(two.OrderBy(s=>s));
   }

   public int GetHashCodeList<Student> item)
   {
     int ret = -1;
     foreach (var s in item)
       ret ^= s.GetHashCode();
     return ret;
   }
}

このソリューションの主な問題は、2つのリスト<>を比較するために使用されるコードです。同じ要素を異なる順序で含むリストは等しいと見なされますか?はいの場合、各リストを事前に並べ替えて順序を変更するか(比較の時間を節約するため)、各リストのコピーを毎回並べ替える必要があります。これにより、追加の時間ペナルティが発生します。ですから、主な質問はあなたのリストの大きさだと思います。1000人未満の学生/100リストの値の場合、パフォーマンスの問題は目立たないはずです。

もう1つの問題はGetHashCodeの実装です。これはO(N)であり、Listはフレームワーク構造であるため、計算値をキャッシュする場所がありません。これを回避するには、StudentListクラスを導入することをお勧めします。このクラスには、比較機能があり(今のところ、外部で指定する必要があります)、キャッシュを使用してハッシュコードを取得します。

また、利用可能な汎用コレクション等価比較器のより良い実装があります。

于 2013-03-27T05:08:01.183 に答える
1

IEquatable<T>との両方Studentに使用できますExam

public class Student: IEquatable<Student>
{
    ...

    public bool Equals(Student other)
    {
        return name == other.name && age == other.age 
                    && lastExam.Equals(other.lastExam);
    }

    public override bool Equals(object obj)
    {
        Student student = obj as Student;
        return Equals(student);
    }

    public override int GetHashCode()
    {
        return name.GetHashCode() ^ 
             age.GetHashCode() ^ lastExam.GetHashCode();
    }
}

の場合Exam

public class Exam: IEquatable<Exam>
{
    ...

    public bool Equals(Exam exam)
    {
        return exam.correct == correct && exam.possible == possible;
    }

    public override bool Equals(object obj)
    {
        Exam exam = obj as Exam;
        return Equals(exam);
    }

    public override int GetHashCode()
    {
        return correct.GetHashCode() ^ possible.GetHashCode();
    }
}

次に、次のカスタムIQualityComparer<T>を作成しList<Student>ます。

public class StudentListComparer : IEqualityComparer<List<Student>>
{
    public bool Equals(List<Student> x, List<Student> y)
    {
        return x.OrderBy(a => a.name)
                .SequenceEqual(y.OrderBy(b => b.name));
    }

    public int GetHashCode(List<Student> obj)
    {
        return obj.Aggregate(0, (current, t) => current ^ t.GetHashCode());
    }
}

次にDistinct、結果を取得できます。

var result = lstStudents.Distinct(new StudentListComparer());
于 2013-03-27T06:55:39.970 に答える