使用.NET 2.0 </t>删除List <t>中的重复项

时间:2012-10-24 04:13:09

标签: c# asp.net .net

当我尝试使用.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;
    }
}

我将所有列表项作为输出。想知道我在哪里做错了。

3 个答案:

答案 0 :(得分:2)

您正在查看的核心思想可以通过操作来描述 - 相等 - 以及数据结构 - 集合。

首先,操作。

你的班级MyOrderingClass已接近你想要的了。您可以使用IComparer<Student>代替IEqualityComparer<Student>,它提供了一种方法来确定两个实例是否相等。确定这一点需要两种方法:Equals当然,GetHashCode是一种&#34;快捷方式&#34;某些数据结构使用的方法,以查看实例是否可能相等。这里需要注意的重要一点是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>的实现可能会有所帮助。这样做的原因是&#34;不同元素的概念&#34;实际上是一个集合概念的定义 - 属于一起的独特元素。 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);

答案 1 :(得分: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;

答案 2 :(得分: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();
                }


            }