TL; T
string
ise T
T
, hangi veri türü olursa olsun, IComparer<T>
gelen IEqualityComparer<T>
elde etmek için bir yöntem arıyorum. Ya da bu sorun için farklı bir çözüme ihtiyacım var.IComparer'dan IEqualityComparer türetmenin bir yolu var mı?
İşte tam hikaye: LFU ilkesiyle basit, genel önbellek yapıyorum. Önkoşul, önbelleklerin büyük/küçük harfe duyarlı veya büyük/küçük harfe duyarlı olup olmadığını seçmek için mümkün olmalıdır - eğer string
önbellek anahtarları için veri türü ise (ki bu gerekli değildir). Öncelikle önbellek için geliştirdiğim çözümde, yüz milyarlarca önbellek araması ve maksimum 100.000 giriş önbellek boyutu bekliyorum. Bu sayılar nedeniyle hemen ayırmalara neden olan (.ToLower().GetHashCode()
vb.) Herhangi bir dize manipülasyonu kullanmaktan vazgeçtim ve bunun yerine standart BCL özellikleri oldukları için IComparer
ve IEqualityComparer
kullanmayı tercih ettim. Bu önbelleğin kullanıcısı, karşılaştırıcıları yapıcıya iletebilir. İşte kod alakalı fragmanları şunlardır:
public class LFUCache<TKey,TValue>
{
private readonly Dictionary<TKey,CacheItem> entries;
private readonly SortedSet<CacheItem> lfuList;
private class CacheItem
{
public TKey Key;
public TValue Value;
public int UseCount;
}
private class CacheItemComparer : IComparer<CacheItem>
{
private readonly IComparer<TKey> cacheKeyComparer;
public CacheItemComparer(IComparer<TKey> cacheKeyComparer)
{
this.cacheKeyComparer = cacheKeyComparer;
if (cacheKeyComparer == null)
this.cacheKeyComparer = Comparer<TKey>.Default;
}
public int Compare(CacheItem x, CacheItem y)
{
int UseCount = x.UseCount - y.UseCount;
if (UseCount != 0) return UseCount;
return cacheKeyComparer.Compare(x.Key, y.Key);
}
}
public LFUCache(int capacity, IEqualityComparer<TKey> keyEqualityComparer,
IComparer<TKey> keyComparer) // <- here's my problem
{
// ...
entries = new Dictionary<TKey, CacheItem>(keyEqualityComparer);
lfuList = new SortedSet<CacheItem>(new CacheItemComparer(keyComparer));
}
// ...
}
keyEqualityComparer
önbellek girdilerini yönetmek için kullanılır (kullanıcı isterse bu yüzden örneğin anahtar "ABC" ve "abc" eşittir). keyComparer
, UseCount
tarafından sıralanmış önbellek girdilerini yönetmek için kullanılır, böylece en az sıklıkla kullanılanı (CacheItemComparer
sınıfında uygulanır) seçmek kolaydır. özel karşılaştırma ile
Örnek Doğru kullanım:
var cache = new LFUCache<string, int>(10000,
StringComparer.InvariantCultureIgnoreCase,
StringComparer.InvariantCultureIgnoreCase);
(O aptal görünüyor, ama StringComparer
hem IComparer<string>
ve IEqualityComparer<string>
uygular.) sorun olduğunu kullanıcı uyumsuz comparers keyComparer
duyarlı (yani harf duyarsız keyEqualityComparer
ve davayı verirse), o zaman en olası sonuç geçersiz LFU istatistikleridir ve bu nedenle en düşük düzeyde önbellek isabetleri olur. Diğer senaryo da istenenden daha azdır. Ayrıca anahtar daha sofistike ise (Tuple<string,DateTime,DateTime>
benzeyen bir şey var), daha da ciddiye almak mümkündür.
Bu nedenle, kurucuda yalnızca tek bir karşılaştırma argümanı kullanmak istiyorum, ancak bu işe yaramaz. yardımı ile IEqualityComparer<T>.Equals()
'u oluşturabiliyorum, ama ben IEqualityComparer<T>.GetHashCode()
'da sıkışıp kaldım - bildiğiniz gibi çok önemlidir. Vakaya duyarlı olup olmadığını kontrol etmek için karşılaştırıcının özel özelliklerine erişebilseydim, hash kodunu almak için CompareInfo
kullanmış olurdum. bana kabul edilebilir performans ve kontrol edilebilir bir bellek tüketimini verir çünkü
Ben 2 farklı veri yapıları bu yaklaşımı gibi - benim laptop etrafında 500.000 önbellek eklemeler/önbellek boyutu 10.000 elemanları ile sn. Dictionary<TKey,TValue>
sadece O verileri bulmak için kullanılan (1) ve O'da SortedSet<CacheItem>
uçlar verileri (n günlük), O içinde lfuList.Min
arayarak kaldırma elemanı bulmak (log n) ve (O de kullanımı sayımını artırmak için bir giriş bulmak log n). çözmek için nasıl
herhangi bir öneriniz bu açıktır. Farklı tasarımlar dahil olmak üzere herhangi bir fikri takdir edeceğim.
Bir olasılık, "IEqualityComparer" ve "IComparer " özelliklerini uygulayan tek bir karşılaştırma parametresi gerektiren statik bir fabrika yöntemi tanımlamak için genel kısıtlamalar kullanmaktır. O zaman en azından iki farklı parametrede aynı nesneye sahip değilsiniz. –
Bu kulağa ilginç geliyor, ancak bir şekilde kodun nasıl görünmesi gerektiğine dair bir fikir edinemiyorum. Birkaç kaba kod satırı paylaşabilir misiniz? ;-) – Endrju
Elbette. Cevabımı gör. –