确保列表中的每个项目都是唯一的?

时间:2014-08-24 12:10:27

标签: c# list filter unique hashset

我们说我有一个1到10.000.000个项目的列表。类型是List。 CustomObj看起来像这样:

class Person 
{
   public string Prename;
   public string Lastname;

   public CustomObj(string pre, string last)
   {
      Prename = pre; 
      Lastname = last;
   }
}

我想确保此列表中的每个人都是独一无二的。因此,如果我尝试添加一个" Tim Stone"并且已经有一个" Tim Stone"在列表中,新的不会被添加或过滤掉。

我尝试使用List.Distinct()函数删除重复项。可悲的是,它对自定义对象的效果并不好,我最终得到了重复项。

HashSet可以,我在寻找什么?如果是这样,实现将如何?

此致

3 个答案:

答案 0 :(得分:1)

如您所述,您可以将它们添加到HashSet,而不是先将它们添加到列表中。覆盖EqualsGetHashCode方法。例如,你可以这样做

public class Person  
{
    public string Prename;
    public string Lastname;


    public Person(string pre, string last)
    {
        Prename = pre; Lastname = last;
    }

    public override bool Equals(object obj)
    {
        Person p = obj as Person;

        //can make this check case insensitive using the overload
        return (Prename + Lastname).Equals(p.Prename + p.Lastname);
    }

    public override int GetHashCode()
    {
        return (Prename + Lastname).GetHashCode();
    }

}

这样,当您将它们添加到HashSet时,不会添加重复项。如果您已有列表,则可以使用HashSet's构造函数重载,如下所示:

HashSet<Person> hsPerson = new HashSet<Person>(myExistingList);

您最终会得到HashSetPerson个不会重复的对象。

我上面的实现假设重复是指一旦他们重新连接就具有相同prenamelastname的人,但您可以将其更改为您喜欢的内容。

答案 1 :(得分:1)

如果您不关心收藏中元素的订单,那么HashSet就可以了。

它的方法几乎与List的方法相同,因为它们实现了ICollectionIEnumerable等通用接口。这是一个样本:

HashSet<Person> people = new HashSet<Person>();
var heko = new Person("heko", "17");
people.Add(heko); // people now contains heko
people.Add(heko); // people still contains only heko since duplicates are not allowed
people.Add(new Person("Nikola", "Dimitroff")); // people contains heko and nikola

有几点需要注意。首先,由于HashSet没有按顺序保留元素,因此您无法通过索引获取元素,即people[0]是无效操作。要枚举集合中的人使用foreach

其次,HashSet在比较项目时使用==运算符和GetHashCode方法。如果您考虑new Person("heko", 17") == new Person("heko", "17")

,请务必重载它们

答案 2 :(得分:0)

如果要对自定义对象使用HashSet<T>或任何Distinct操作,可以使自定义对象实现IEquatable界面(遵循该页面上的所有指导,包括覆盖GetHashCode)。完成后,BCL集合和LINQ操作将按照您希望的方式运行。

您应该知道,使GetHashCode使用可以更改的类的属性可能会导致非常糟糕的事情发生(例如,字典或集合中的项可能会“丢失”)。如果您无法使重要属性不可变,则可以通过创建IList<T>的自定义实现来满足您的要求,该实现包装标准List<T>并实现集合类型的Add方法,如这样:

public void Add(Person person)
{
   if (!_list.Any(p => p.Prename == person.PreName && p.Lastname == person.Lastname))
   {
      _list.Add(person);
   }
}

此解决方案的效率会低得多,但可能会为您节省一些令人费解的错误。