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

C# 确保列表中的每个项目都是唯一的?,c#,list,filter,unique,hashset,C#,List,Filter,Unique,Hashset,假设我有一个1到10.000.000项的列表。类型为列表。CustomObj如下所示: class Person { public string Prename; public string Lastname; public CustomObj(string pre, string last) { Prename = pre; Lastname = last; } } HashSet<Person> hsPerson =

假设我有一个1到10.000.000项的列表。类型为列表。CustomObj如下所示:

class Person 
{
   public string Prename;
   public string Lastname;

   public CustomObj(string pre, string last)
   {
      Prename = pre; 
      Lastname = last;
   }
}
HashSet<Person> hsPerson = new HashSet<Person>(myExistingList);
public void Add(Person person)
{
   if (!_list.Any(p => p.Prename == person.PreName && p.Lastname == person.Lastname))
   {
      _list.Add(person);
   }
}
我想确定的是,名单上的每个人都是独一无二的。因此,如果我尝试添加一个“Tim Stone”,而列表中已经有一个“Tim Stone”,那么新的一个将不会被添加或过滤掉

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

哈希集可能是我要找的吗?如果是的话,实施情况如何


关于

您可以将它们添加到您提到的
哈希集中,而不是首先将它们添加到列表中。重写
Equals
GetHashCode
方法。例如,您可以这样做

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的
构造函数重载:

class Person 
{
   public string Prename;
   public string Lastname;

   public CustomObj(string pre, string last)
   {
      Prename = pre; 
      Lastname = last;
   }
}
HashSet<Person> hsPerson = new HashSet<Person>(myExistingList);
public void Add(Person person)
{
   if (!_list.Any(p => p.Prename == person.PreName && p.Lastname == person.Lastname))
   {
      _list.Add(person);
   }
}
HashSet hsPerson=newhashset(myExistingList);
您将得到一个
Person
对象的
HashSet
,该对象不会有重复项


我上面的实现假设一个重复的人在连接后具有相同的
prename
lastname
,但是您可以将其更改为您喜欢的内容。

如果您不关心集合中元素的顺序,那么这就是方法

它的方法几乎与
List
的方法相同,因为它们实现了诸如
ICollection
IEnumerable
等公共接口。以下是一个示例:

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=newhashset();
var heko=新人(“heko”,“17”);
人物。添加(heko);//人们现在包含了heko
人物。添加(heko);//因为不允许重复,所以人们仍然只包含heko
人物。添加(新人物(“尼古拉”、“迪米特洛夫”);//人们包括赫科和尼古拉
有几件事需要注意。首先,由于
HashSet
没有保持元素的顺序,因此无法通过元素的索引获取元素,即
people[0]
是无效的操作。要枚举集合中的人员,请使用
foreach


其次,
HashSet
在比较项目时使用
=
运算符和
GetHashCode
方法。如果你认为代码<新的人(“Heo”,17)=新的人(“HEKO”,“17”)< /P> > P > >如果你想用你的自定义对象使用<代码> HasStuts< /C>或任何<代码>不同的< /代码>操作,你可以让你的自定义对象实现接口。(遵循该页面上的所有指导,包括覆盖
GetHashCode
)。完成后,BCL集合和LINQ操作将按照您希望的方式运行

您应该知道,使
GetHashCode
使用可以更改的类的属性可能会导致非常糟糕的事情发生(例如,字典或集合中的项目可能会“丢失”)。如果无法使重要属性保持不变,则可以通过创建一个自定义的
IList
实现来满足您的要求,该实现封装了一个标准的
列表
,并实现集合类型的
Add
方法,如下所示:

class Person 
{
   public string Prename;
   public string Lastname;

   public CustomObj(string pre, string last)
   {
      Prename = pre; 
      Lastname = last;
   }
}
HashSet<Person> hsPerson = new HashSet<Person>(myExistingList);
public void Add(Person person)
{
   if (!_list.Any(p => p.Prename == person.PreName && p.Lastname == person.Lastname))
   {
      _list.Add(person);
   }
}

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

如果
Prename
Lastname
在仍处于
HashSet
中时发生更改,会发生什么情况?根据您的
GetHashCode
方法,它们不会被找到。我假设OP只是关心添加或过滤列表。如果更新whilst在一个集合中,用一种自定义的方法来检查重复,实现
IEqualityComparer
接口可能是有意义的。