确保列表中的每个项目都是唯一的
本文关键字:唯一 项目 列表 确保 | 更新日期: 2023-09-27 18:19:12
假设我有一个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",则不会添加或过滤掉新的"Tim Stone"。
我尝试使用List.Distinct()函数来删除重复项。遗憾的是,它不能很好地处理自定义对象,我最终得到了重复的对象。
可以一个哈希集,我正在寻找什么?如果是这样,实现会是什么样子?
对
您可以将它们添加到您提到的HashSet
中,而不是首先将它们添加到List中。覆盖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
时,将不会添加重复项。如果你已经有了一个列表,你可以像这样使用HashSet's
构造函数重载:
HashSet<Person> hsPerson = new HashSet<Person>(myExistingList);
你最终会得到一个HashSet
的Person
对象,它不会有重复的。
我上面的实现假设一个重复的人有相同的prename
和lastname
一旦他们被连接,但你可以改变它到你喜欢的
如果您不关心集合中元素的顺序,那么HashSet
就是您的选择。
它的方法几乎与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[0]
是无效的操作。要枚举集合中的人员,请使用foreach
。
其次,HashSet
在比较项时使用==
运算符和GetHashCode
方法。如果您认为new Person("heko", 17") == new Person("heko", "17")
.
如果您想使用HashSet<T>
或任何Distinct
操作与您的自定义对象,您可以使您的自定义对象实现等价接口(遵循该页上的所有指导,包括覆盖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);
}
}
这个解决方案的效率要低得多,但可能会为您节省一些令人费解的bug。