HashSet如何比较元素是否相等? [英] How does HashSet compare elements for equality?
问题描述
我有一个类别为 IComparable
:
public class a : IComparable
{
public int Id { get; set; }
public string Name { get; set; }
public a(int id)
{
this.Id = id;
}
public int CompareTo(object obj)
{
return this.Id.CompareTo(((a)obj).Id);
}
}
当我将此类的对象列表添加到散列集:
When I add a list of object of this class to a hash set:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(a1);
一切都很好, ha.count
是 2
,但是:
Everything is fine and ha.count
is 2
, but:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(new a(1));
现在 ha.count
是 3
。
- 为什么不
HashSet
尊重a
的CompareTo
方法。 - 是
HashSet
拥有唯一对象列表的最佳方法?
- Why doesn't
HashSet
respecta
'sCompareTo
method. - Is
HashSet
the best way to have a list of unique objects?
推荐答案
它使用 IEqualityComparer< T>
( EqualityComparer< T>。默认
,除非您在构造上指定了另一个)。
It uses an IEqualityComparer<T>
(EqualityComparer<T>.Default
unless you specify a different one on construction).
将元素添加到集合中时,它会将使用 IEqualityComparer< T> .GetHashCode
查找哈希码,并存储哈希码和元素(当然,在检查元素是否已在集合中之后)
When you add an element to the set, it will find the hash code using IEqualityComparer<T>.GetHashCode
, and store both the hash code and the element (after checking whether the element is already in the set, of course).
要查找元素,它将首先使用 IEqualityCompar er< T> .GetHashCode
查找哈希码,然后对于具有相同哈希码的所有元素,它将使用 IEqualityComparer< T> ;.等于
比较实际的相等性。
To look an element up, it will first use the IEqualityComparer<T>.GetHashCode
to find the hash code, then for all elements with the same hash code, it will use IEqualityComparer<T>.Equals
to compare for actual equality.
这意味着您有两个选择:
That means you have two options:
- 将自定义
IEqualityComparer< T>
传递到构造函数中。如果您不能修改T
本身,或者想要一个非默认的相等关系(例如,所有具有负用户ID的用户都被认为是等于)。这几乎永远不会在类型本身上实现(即Foo
不实现IEqualityComparer< Foo>
),但是在 - 通过覆盖
GetHashCode
和来实现类型本身的相等性等于(对象)
。理想情况下,还要在类型中实现IEquatable< T>
,尤其是在它是值类型的情况下。这些方法将由默认的相等比较器调用。
- Pass a custom
IEqualityComparer<T>
into the constructor. This is the best option if you can't modify theT
itself, or if you want a non-default equality relation (e.g. "all users with a negative user ID are considered equal"). This is almost never implemented on the type itself (i.e.Foo
doesn't implementIEqualityComparer<Foo>
) but in a separate type which is only used for comparisons. - Implement equality in the type itself, by overriding
GetHashCode
andEquals(object)
. Ideally, implementIEquatable<T>
in the type as well, particularly if it's a value type. These methods will be called by the default equality comparer.
请注意,这与有序无关。 em>比较-这很有意义,因为在某些情况下,您可以轻松指定相等性,但不能指定总顺序。基本上,这与 Dictionary< TKey,TValue>
相同。
Note how none of this is in terms of an ordered comparison - which makes sense, as there are certainly situations where you can easily specify equality but not a total ordering. This is all the same as Dictionary<TKey, TValue>
, basically.
如果要使用排序,而不仅仅是相等比较,您应该使用 <$ .NET 4中的c $ c> SortedSet< T> -允许您指定 IComparer< T>
而不是 IEqualityComparer< T>
。这将使用 IComparer< T> .Compare
-将委托给 IComparable< T> .CompareTo
或 IComparable.CompareTo
(如果您使用的是 Comparer< T>。默认值
。
If you want a set which uses ordering instead of just equality comparisons, you should use SortedSet<T>
from .NET 4 - which allows you to specify an IComparer<T>
instead of an IEqualityComparer<T>
. This will use IComparer<T>.Compare
- which will delegate to IComparable<T>.CompareTo
or IComparable.CompareTo
if you're using Comparer<T>.Default
.
这篇关于HashSet如何比较元素是否相等?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!