4

当我尝试使用 .NET 2.0 从 List 中删除重复项时,我无法获得预期的结果。

    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已经接近你想要的了。而不是IComparer<Student>,您可以使用IEqualityComparer<Student>which 提供一种方法来确定两个实例是否相等。确定这一点需要两种方法:Equals当然,GetHashCode这是某些数据结构用来查看实例是否可能相等的一种“快捷方式”方法。这里要注意的重要一点是, 的实现GetHashCode涉及用于确定相等性的相同值。

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

第二,数据结构。

可以通过使用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 提到:默认等于仅支持引用相等。这可能很有用http://msdn.microsoft.com/en-US/library/bsc2ak47(v=vs.80).aspx

       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 回答