Search code examples
c#searchbinarycustom-type

Binary searching array of custom type


I have an array A of objects, each with the public field Value (double) which have random doubles between 0 and 1. A is sorted by this field. I create double random = 0.25. Now I want to find the first object from A with A[index].Value >= random. Can I do this with int index = Array.BinarySearch() in some way?


Solution

  • Here is an implementation of BinarySearch that you can use. In addition to the other arguments that would normally be accepted, it also accepts a selector which determines the actual object that should be compared for each item, and for the value to find it accepts a value of that type, rather than the type of the array.

    public static int BinarySearch<TSource, TKey>(this IList<TSource> collection
        , TKey item, Func<TSource, TKey> selector, Comparer<TKey> comparer = null)
    {
        return BinarySearch(collection, item, selector, comparer, 0, collection.Count);
    }
    private static int BinarySearch<TSource, TKey>(this IList<TSource> collection
        , TKey item, Func<TSource, TKey> selector, Comparer<TKey> comparer
        , int startIndex, int endIndex)
    {
        comparer = comparer ?? Comparer<TKey>.Default;
    
        while (true)
        {
            if (startIndex == endIndex)
            {
                return startIndex;
            }
    
            int testIndex = startIndex + ((endIndex - startIndex) / 2);
            int comparision = comparer.Compare(selector(collection[testIndex]), item);
            if (comparision > 0)
            {
                endIndex = testIndex;
            }
            else if (comparision == 0)
            {
                return testIndex;
            }
            else
            {
                startIndex = testIndex + 1;
            }
        }
    }
    

    To use it is simple enough:

    public class Foo
    {
        public double Value { get; set; }
    }
    
    private static void Main(string[] args)
    {
        Foo[] array = new Foo[5];
        //populate array with values
        array.BinarySearch(.25, item => item.Value);
    }