Saya memiliki kelas yaitu 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);
}
}
Ketika saya menambahkan daftar objek dari kelas ini ke kumpulan hash:
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);
Semuanya baik-baik saja dan ha.count
ini 2
, tapi:
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));
Sekarang ha.count
adalah 3
.
- Mengapa tidak
HashSet
menghormatia
'sCompareTo
metode. - Apakah
HashSet
cara terbaik untuk memiliki daftar benda unik?
IEqualityComparer<T>
dalam konstruktor atau implementasikan di kelasa
. msdn.microsoft.com/en-us/library/bb301504(v=vs.110).aspxJawaban:
Menggunakan
IEqualityComparer<T>
(EqualityComparer<T>.Default
kecuali Anda menentukan yang berbeda pada konstruksi).Ketika Anda menambahkan elemen ke set, itu akan menemukan kode hash menggunakan
IEqualityComparer<T>.GetHashCode
, dan menyimpan kode hash dan elemen (setelah memeriksa apakah elemen sudah di set, tentu saja).Untuk mencari elemen, pertama-tama akan menggunakan
IEqualityComparer<T>.GetHashCode
untuk menemukan kode hash, kemudian untuk semua elemen dengan kode hash yang sama, itu akan digunakanIEqualityComparer<T>.Equals
untuk membandingkan kesetaraan yang sebenarnya.Itu berarti Anda memiliki dua opsi:
IEqualityComparer<T>
ke konstruktor. Ini adalah opsi terbaik jika Anda tidak dapat memodifikasiT
sendiri, atau jika Anda ingin hubungan kesetaraan non-standar (misalnya "semua pengguna dengan ID pengguna negatif dianggap sama"). Ini hampir tidak pernah diimplementasikan pada tipe itu sendiri (yaituFoo
tidak mengimplementasikanIEqualityComparer<Foo>
) tetapi dalam tipe terpisah yang hanya digunakan untuk perbandingan.GetHashCode
danEquals(object)
. Idealnya, implementasikanIEquatable<T>
dalam tipe juga, terutama jika itu tipe nilai. Metode-metode ini akan dipanggil oleh pembanding kesetaraan default.Perhatikan bagaimana tidak satu pun dari ini dalam hal perbandingan yang dipesan - yang masuk akal, karena pasti ada situasi di mana Anda dapat dengan mudah menentukan kesetaraan tetapi bukan total pemesanan. Ini semua sama dengan
Dictionary<TKey, TValue>
, pada dasarnya.Jika Anda menginginkan set yang menggunakan pemesanan alih-alih hanya perbandingan kesetaraan, Anda harus menggunakan
SortedSet<T>
dari .NET 4 - yang memungkinkan Anda untuk menentukanIComparer<T>
bukanIEqualityComparer<T>
. Ini akan menggunakanIComparer<T>.Compare
- yang akan didelegasikan keIComparable<T>.CompareTo
atauIComparable.CompareTo
jika Anda menggunakanComparer<T>.Default
.sumber
IEqualityComparer<T>.GetHashCode/Equals()
adalah dengan menerapkanEquals
danGetHashCode
padaT
dirinya sendiri (dan saat Anda melakukan itu, Anda juga akan menerapkan mitra yang sangat diketikkan : -bool IEquatable<T>.Equals(T other)
)Equals
danGetHashCode
cukup - seperti yang disebutkan dalam jawaban @ tyriker.IComparable
(atauIComparer
dalam hal ini) Anda tidak boleh diminta untuk menerapkan kesetaraan secara terpisah (tapi adilGetHashCode
). Dalam arti antarmuka komparabilitas harus mewarisi dari antarmuka kesetaraan. Saya mengerti manfaat kinerja dalam memiliki dua fungsi yang terpisah (di mana Anda dapat mengoptimalkan kesetaraan secara terpisah hanya dengan mengatakan jika ada sesuatu yang sama atau tidak) tapi masih .. Sangat membingungkan jika ketika Anda telah ditentukan ketika kasus yang sama dalamCompareTo
fungsi dan kerangka wont mempertimbangkan bahwa.a.boolProp == b.boolProp ? 1 : 0
atau harus itua.boolProp == b.boolProp ? 0 : -1
ataua.boolProp == b.boolProp ? 1 : -1
. Yuk!Berikut ini klarifikasi pada bagian dari jawaban yang tidak diucapkan: Jenis objek Anda
HashSet<T>
tidak harus diimplementasikanIEqualityComparer<T>
tetapi alih-alih hanya perlu menggantiObject.GetHashCode()
danObject.Equals(Object obj)
.Alih-alih ini:
Anda melakukan ini:
Ini halus, tetapi ini membuat saya tersandung untuk bagian yang lebih baik dari hari mencoba untuk membuat HashSet berfungsi seperti yang dimaksudkan. Dan seperti orang lain katakan,
HashSet<a>
akan berakhir menelepona.GetHashCode()
dana.Equals(obj)
seperlunya ketika bekerja dengan set.sumber
bool IEquatable<T>.Equals(T other)
untuk mendapatkan efisiensi sedikit tetapi yang lebih penting manfaat kejelasan. Untuk alasan obv, di samping kebutuhan untuk mengimplementasikanGetHashCode
bersamaIEquatable<T>
, dokumen untuk IEquatable <T> menyebutkan bahwa untuk tujuan konsistensi Anda juga harus menggantiobject.Equals
konsistensiovveride getHashcode
bekerja, tapioverride bool equals
mendapat kesalahan: tidak ada metode ditemukan override. ada ide?public class a : IEqualityComparer<a> {
, lalunew HashSet<a>(a)
.HashSet
menggunakanEquals
danGetHashCode()
.CompareTo
untuk set yang dipesan.Jika Anda menginginkan objek unik, tetapi Anda tidak peduli dengan urutan iterasi mereka,
HashSet<T>
biasanya merupakan pilihan terbaik.sumber
constructor HashSet menerima objek apa yang mengimplementasikan IEqualityComparer untuk menambahkan objek baru. jika Anda ingin menggunakan metode di HashSet Anda tidak akan mengesampingkan Equals, GetHashCode
sumber