4

.NET 2.0を使用してリストから重複アイテムを削除しようとしましたが、期待した結果を得ることができませんでした。

    List<Student> list1 = new List<Student>();

    Student s = new Student();
    s.Age = "35";
    s.Name = "Nazmul";
    list1.Add(s);

    s = new Student();
    s.Age = "35";
    s.Name = "Nazmul";
    list1.Add(s);

    s = new Student();
    s.Age = "35";
    s.Name = "Nazmul";
    list1.Add(s);

    s = new Student();
    s.Age = "35";
    s.Name = "Nazmul";
    list1.Add(s);

    IComparer<Student> compare = new MyOrderingClass();

    list1.Sort(compare);
    Int32 index = 0;

    while (index < list1.Count - 1)
    {

        if (list1[index].Equals(list1[index + 1]))
        {
            list1.RemoveAt(index);
        }
        else
        {
            index++;
        }
    }

    foreach (Student st in list1)
    {

        Response.Write("Name:" + st.Name);
        Response.Write("Age:" + st.Age + "<br/>");
    }

上記で使用したクラスとメソッドを以下に示します。

public class Student
{
    private String name;
    private String age;
    public String Name
    {
        get { return name; }
        set { name = value; }
    }
    public String Age { 
        get { return age; } 
        set { age = value; } 
    }
}

public class MyOrderingClass : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        int compareName = x.Name.CompareTo(y.Name);
        if (compareName == 0)
        {
            return x.Age.CompareTo(y.Age);
        }
        return compareName;
    }
}

すべてのリストアイテムを出力として取得しています。私がどこで間違っているのか疑問に思います。

4

3 に答える 3

2

あなたが見ている核となるアイデアは、操作 - 等価性 - とデータ構造 - セットで説明できます。

まず、操作。

あなたのクラスMyOrderingClassは、あなたがここで望むものに近づいています。の代わりに、 2 つのインスタンスが等しいかどうかを判断する方法を提供する which をIComparer<Student>使用できます。これを決定するために必要なメソッドIEqualityComparer<Student>が 2 つあります。ここで注意すべき重要なことは、 の実装には、等値の決定に使用されるのと同じ値が含まれることです。EqualsGetHashCodeGetHashCode

public class MyOrderingClass : IEqualityComparer<Student>, IComparer<Student>
{   
    public int Compare(Student x, Student y)   
    {   
        if (ReferenceEquals(x, y))
        {
            return 0;
        }

        if (ReferenceEquals(x, null))
        {
            throw new ArgumentException("x");
        }

        if (ReferenceEquals(y, null))
        {
            throw new ArgumentException("y");
        }

        // Optional: use StringComparer.CurrentCultureIgnoreCase.CompareTo or maybe others 
        // from http://msdn.microsoft.com/en-us/library/system.stringcomparer.aspx
        int compareName = x.Name.CompareTo(y.Name);

        if (compareName == 0)   
        {   
            return x.Age.CompareTo(y.Age);   
        }   

        return compareName;   
    }

    public int GetHashCode(Student student)
    {
        if(student == null)
        {
            throw new ArgumentNullException("student");
        }

        unchecked
        {
            return (student.Name ?? String.Empty).GetHashCode() ^ student.Age;
        }
    }

    public bool Equals(Student x, Student y)
    {
        return Compare(x, y) == 0;
    }
}   

2 つ目は、データ構造です。

個別のオブジェクトのコレクションを持つという考えは、Distinct拡張メソッドを使用して実現できますが、ISet<T>-の実装を調べると役立つ場合がありますHashSet<T>。この理由は、「個別の要素」の概念が実際にはセットの概念の定義であるためです。つまり、一緒に属する一意の要素です。のHashSet<T>インスタンスを使用しますIEqualityComparer<T>- デフォルトではEqualityComparer<T>.Default、参照等価を行うものを使用します。もちろん、新しく強化されたMyOrderingClass. このDistinctメソッドは、ハッシュベースのセットを使用して、既に認識され生成された要素を追跡し、その目的のために、IEqualityComparer<T>この内部セットに渡すインスタンスを取得できることがわかりました。

基本的な概念を調べたので、コードを見てみましょう。

List<Student> list1 = new List<Student>();

// ... add instances with the same name and age

// option 1: use HashSet<T>
var set = new HashSet<Student>(list1, new MyOrderingClass());
Assert.Equal(1, set.Count);

// option 2: use Distinct
var distinct = list1.Distinct(new MyOrderingClass());
Assert.Equal(1, distinct.Count());

// option 3: when you don't have a proper set (e.g. .Net 2.0)
Dictionary<Student, Object> d = new Dictionary<Student, Object>(new MyOrderingClass());
list1.ForEach(delegate(Student e) { d[e] = null; });
Assert.Equal(1, d.Count);
于 2012-10-24T04:53:56.343 に答える
2

.NET 2.0 では、Dictionary<>クラスを使用して個別の値を取得できます。おそらく、すぐに使用できる機能を使用するのが最も効率的なアプローチになるでしょう。明らかに、.NET 3.5 以降ではDistinct拡張メソッドを使用します。ここでは、.NET 2.0 の実装を追加しました。

public class Student : IEquatable<Student>
{
    private String name;
    private String age;
    public String Name
    {
        get { return name; }
        set { name = value; }
    }
    public String Age
    {
        get { return age; }
        set { age = value; }
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;

            hash = hash * 23 + ((Age == null) ? 0 : Age.GetHashCode());
            hash = hash * 23 + ((Name == null) ? 0 : Name.GetHashCode());

            return hash;
        }
    }

    public bool Equals(Student other)
    {
        if (other == null)
        {
            return false;
        }

        return Age == other.Age && Name == other.Name;
    }

    public override bool Equals(object obj)
    {
         if (obj == null) return false;
         if (obj.GetType() != typeof(Student)) return false;

         return Equals((Student)obj);
    }
}

Dictionary<Student, bool> dict = new Dictionary<Student, bool>();

foreach (Student student in list1)
{
    if (!dict.ContainsKey(student))
    {
        dict.Add(student, false);
    }
}

ICollection<Student> distinctList = dict.Keys;
于 2012-10-24T05:01:26.240 に答える
1

pmtamal について言及: デフォルトの equals は参照の等価性のみをサポートします

       public class Student
            {
                private String name;
                private String age;
                public String Name
                {
                    get { return name; }
                    set { name = value; }
                }
                public String Age
                {
                    get { return age; }
                    set { age = value; }
                }

                public override bool Equals(object obj)
                {
                    Student st = obj as Student;
                    if(st != null ){
                        return (this.name.Trim().ToLower().Equals(st.name.Trim().ToLower()) && this.age == st.age);
                    }
                    return base.Equals(obj);
                }

                public override int GetHashCode()
                {
                   return base.GetHashCode();
                }


            }
于 2012-10-24T04:27:12.927 に答える