Yeni düzenleme: Diğerleri için yararlı olacağından, aşağıdaki fazladan ikili aramaları aşağıda bırakacağım ve işte tam olarak istediğinizi düşündüğüm son bir seçenek. Aradığınız öğe "belirtilenden daha az", belirtilmiş olandan "büyük" ise negatif bir sayı ve doğruysa 0 olmalıdır.
public static int BinarySearchForMatch<T>(this IList<T> list,
Func<T,int> comparer)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max)/2;
int comparison = comparer(list[mid]);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
Eski düzenleme: aşağıda orijinal cevabını bırakacağım, ama burada diğer iki seçenek vardır.
İlki, kaynak verilerden bir anahtar türüne bir yansıtma alır ve bulmak için anahtarı belirler. Karşılaştırma kendisi sadece bu anahtar türü için varsayılan şekilde yapılır:
public static int BinarySearchBy<TSource,TKey>(this IList<TSource> list,
Func<TSource,TKey> projection, TKey key)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max)/2;
TKey midKey = projection(list[mid]);
int comparison = Comparer<TKey>.Default.Compare(midKey, key);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
ikinci aradığımız anahtarla listeden bir öğe karşılaştırmak yerine bir Func sürer. Kod elbette, neredeyse tamamen aynıdır - bu değişikliği sadece karşılaştırma var: Bu ikisi test edilmemiştir
public static int BinarySearchBy<TSource,TKey>(this IList<TSource> list,
Func<TSource,TKey,int> comparer, TKey key)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max)/2;
int comparison = comparer(list[mid], key);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
, ama en azından derlemek mi :)
Orjinal cevap:
List<T>.BinarySearch
'u IComparer<T>
ile kullanabilirsiniz.IComparer<T>
kendi uygulamanızı yazmak zorunda değilsiniz - MiscUtil numaralı telefondan, Comparison<T>
temsilcisinden bir IComparer<T>
oluşturur. Bu sadece ilk üç koşulu gösterir, ancak ikili arama geri kalanından sonuncusu çalışır. Aslında, bu kadar kısa bir kod, ben de buraya yapıştırıp yapıştırabilirim (sans yorumlar).
public sealed class ComparisonComparer<T> : IComparer<T>
{
readonly Comparison<T> comparison;
public ComparisonComparer(Comparison<T> comparison)
{
if (comparison == null)
{
throw new ArgumentNullException("comparison");
}
this.comparison = comparison;
}
public int Compare(T x, T y)
{
return comparison(x, y);
}
}
Yani böyle bir şey yapmak olabilir:
var comparer = new ComparisonComparer<Person>((p1, p2) => p1.ID.CompareTo(p2.ID));
int index = list.BinarySearch(employee, comparer);
MiscUtil da olan bir ProjectionComparer
ilginizi olabilir - sadece sadece LINQ ile OrderBy
olduğu gibi bir projeksiyon belirtmek - ama gerçekten bağlıdır kullanım durumunuz.
En yeni cevabınızı beğendim. İçinde bir yazım hatası olduğunu düşünüyorum T <-> TSource – BCS
Oops. Düzeltecek. –
Hey Jon, yöntemin sonunda neden en az geri döndüğünüzü açıklayabilir misiniz? Bu durumda bitleri çevirmenin öneminin ne olduğundan emin değilim. –