Wrap bir IEqualityComparer temsilci
Birkaç Etmeniz.Sayısız işlevleri IEqualityComparer<T>
al. delegate(T,T)=>bool
IEqualityComparer<T>
hayata uyum sağlayan uygun kapsayıcı bir sınıf var mı? Kolay yazmak için yeterli eğer doğru bir hashcode tanımlama ile ilgili sorunlar göz ardı ederseniz () ama eğer out-of-the-box bir çözüm varsa bilmek isterim.
Özellikle, Dictionary
s üzerinde küme işlemleri üyelik, farklı kurallara göre değerlerini koruyarak () tanımlamak için sadece Tuşlarını kullanarak yapmak istiyorum.
CEVAP
GetHashCode
önemi üzerinde
Diğerleri zaten herhangi bir özel IEqualityComparer<T>
uygulama gerçeğini yorumladıgerçekten GetHashCode
bir yöntem içermelidir; ama kimse bir açıklama yapmadığınınedenherhangi bir ayrıntı.
İşte bu yüzden. Sorunuzu özellikle SERİ uzatma yöntemleri; yaklaşık bahsedertümbu hash kodları düzgün çalışması için kullanır, onlar içten verimliliği için karma tablo kullanmak için.
Örneğin Distinct
. Eğer kullanılan tüm Equals
bir yöntemi olsaydı bu uzantı yöntemi etkilerini göz önünde bulundurun. Nasıl bir öğe zaten eğer sadece Equals
eğer bir sıra ile taranmış olup olmadığını mı? Çoktan baktım ve bir maç için kontrol değerleri tüm koleksiyonu numaralandırma. Bu kötü durum O(N . kullanarak Distinct
neden olur ^sup>2) (N) (O) yerine algoritma!
Neyse ki, bu durum böyle değil. Distinct
gelmezsadeceEquals
; GetHashCode
de kullanır. Aslındakesinlikledeğildüzgün bir doğru malzemeler IEqualityComparer<T>
GetHashCode
olmadan bir iş. Aşağıda yapmacık bir örnek bu fotoğraf.
Demek şu tipi var:
class Value
{
public string Name { get; private set; }
public int Number { get; private set; }
public Value(string name, int number)
{
Name = name;
Number = number;
}
public override string ToString()
{
return string.Format("{0}: {1}", Name, Number);
}
}
Şimdi List<Value>
bir ben var ve farklı bir ad ile tüm öğeleri bulmak istiyorum diyelim. Bu Distinct
için mükemmel bir senaryo, özel bir eşitlik karşılaştırıcısı kullanarak. Hadi Aku's answer Comparer<T>
sınıfı kullanın:
var comparer = new Comparer<Value>((x, y) => x.Name == y.Name);
Eğer Name
aynı özelliği Value
öğeleri bir sürü var şimdi, Eğer bir değer Distinct
, sağ tarafından döndürülen içine çökmesi lazım? Bakalım...
var values = new List<Value>();
var random = new Random();
for (int i = 0; i < 10; i)
{
values.Add("x", random.Next());
}
var distinct = values.Distinct(comparer);
foreach (Value x in distinct)
{
Console.WriteLine(x);
}
Çıkış:
x: 1346013431 x: 1388845717 x: 1576754134 x: 1104067189 x: 1144789201 x: 1862076501 x: 1573781440 x: 646797592 x: 655632802 x: 1206819377
Hmm, bu da işe yaramadı, değil mi?
Ne GroupBy
? Hadi deneyelim:
var grouped = values.GroupBy(x => x, comparer);
foreach (IGrouping<Value> g in grouped)
{
Console.WriteLine("[KEY: '{0}']", g);
foreach (Value x in g)
{
Console.WriteLine(x);
}
}
Çıkış:
[KEY = 'x: 1346013431'] x: 1346013431 [KEY = 'x: 1388845717'] x: 1388845717 [KEY = 'x: 1576754134'] x: 1576754134 [KEY = 'x: 1104067189'] x: 1104067189 [KEY = 'x: 1144789201'] x: 1144789201 [KEY = 'x: 1862076501'] x: 1862076501 [KEY = 'x: 1573781440'] x: 1573781440 [KEY = 'x: 646797592'] x: 646797592 [KEY = 'x: 655632802'] x: 655632802 [KEY = 'x: 1206819377'] x: 1206819377
Tekrar: bir işe yaramadı.
Eğer düşünürsen, gayet mantıklı Distinct
kullanmak HashSet<T>
(ya da eşdeğer) dahili ve GroupBy
kullanmak gibi bir şey Dictionary<TKey, List<T>>
DAHİLİ olarak. Bu yöntemler işe yaramazsa, neden bu açıklayabilir misiniz? Bunu deneyelim:
var uniqueValues = new HashSet<Value>(values, comparer);
foreach (Value x in uniqueValues)
{
Console.WriteLine(x);
}
Çıkış:
x: 1346013431 x: 1388845717 x: 1576754134 x: 1104067189 x: 1144789201 x: 1862076501 x: 1573781440 x: 646797592 x: 655632802 x: 1206819377
Evet... her şey anlam kazanmaya başladı?
Umarım bu örnekler: GetHashCode
IEqualityComparer<T>
herhangi uygun bir uygulama da dahil olmak üzere neden bu kadar önemli olduğunu açık.
Orijinal cevap
orip's answer genişletme:
Burada yapılabilecek iyileştirmeler bir çift vardır.
- Önce
Func<T, TKey>
yerineFunc<T, object>
;keyExtractor
gerçek başlı başına değer tipi anahtarları boks önleyecek bir alırdım. - İkinci, istiyorum aslında ekleyin
where TKey : IEquatable<TKey>
kısıtlama; bu-ecek önlemek boksEquals
arama (object.Equals
alırobject
parametre; gerekirIEquatable<TKey>
uygulama için birTKey
parametre olmadan boks). Açıkçası bu çok ciddi bir kısıtlama teşkil edebilir, kısıtlama olmadan, temel bir sınıf ve türetilmiş bir sınıf yapabilir.
Ortaya çıkan kod gibi görünebilir:
public class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
{
protected readonly Func<T, TKey> keyExtractor;
public KeyEqualityComparer(Func<T, TKey> keyExtractor)
{
this.keyExtractor = keyExtractor;
}
public virtual bool Equals(T x, T y)
{
return this.keyExtractor(x).Equals(this.keyExtractor(y));
}
public int GetHashCode(T obj)
{
return this.keyExtractor(obj).GetHashCode();
}
}
public class StrictKeyEqualityComparer<T, TKey> : KeyEqualityComparer<T, TKey>
where TKey : IEquatable<TKey>
{
public StrictKeyEqualityComparer(Func<T, TKey> keyExtractor)
: base(keyExtractor)
{ }
public override bool Equals(T x, T y)
{
// This will use the overload that accepts a TKey parameter
// instead of an object parameter.
return this.keyExtractor(x).Equals(this.keyExtractor(y));
}
}
Olay bildirimi anonim boş bir temsilci...
İç içe geçmiş Geri yükseklik değil...
iPhone Uygulaması Temsilci doğru kulla...
Varlık Çerçevesi - türü Olamaz 'd...
word-wrap:sözcük sonu IE8 çalışmıyor...