6

I want to use List.BinarySearch() with a custom item type. The custom type does not implement IComparable<T>; instead I have several static Comparison<T> functions that I call because at various points I want to sort the list on different criteria. Plus I think it adds clarity since the way you are sorting can be described by the function name. Now I want to do a binary search on the list. I wanted to use one of my comparison functions, only to find that List.BinarySearch() doesn't have an overload that accepts Comparison<T>, only IComparer<T>. I try to avoid IComparer<T> because it seems silly to me to have a separate class just for comparing objects. Why doesn't List.BinarySearch() have overloads that take Comparison<T> in addition to IComparer<T>? And is there any way to use my existing Comparison<T> functions in List.BinarySearch()?

Craig W
  • 4,390
  • 5
  • 33
  • 51

3 Answers3

11

It's very easy to create an IComparer<T> from a Comparison<T> - here's a (slightly amended) class from MiscUtil which you're welcome to use:

/// <summary>
/// Utility to build an IComparer implementation from a Comparison delegate,
/// and a static method to do the reverse.
/// </summary>
public class ComparisonComparer<T> : IComparer<T>
{
    private 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);
    }
}

You could also add an extension method to List<T> to do this for you:

public static int BinarySearch<T>(this List<T> list, Comparison<T> comparison)
{
    return list.BinarySearch(new ComparisonComparer(comparison));
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I guess this is the best solution, although I'm not overly fond of it. I am still very curious about why the overloads don't exist to use Comparison directly. – Craig W Dec 07 '11 at 00:15
  • 1
    @Craig: As ever, there's a cost to introducing anything. I suspect that the BCL maintainers feel it doesn't quite make the bar of utility against cost. – Jon Skeet Dec 07 '11 at 05:08
  • @JonSkeet: I don't see why that would be, since there's an equivalent overload for `.Sort()` that does use `Comparison`. I think they just overlooked it. – BlueRaja - Danny Pflughoeft Jul 25 '13 at 21:25
  • @BlueRaja-DannyPflughoeft: It may well not have been the same person making the decision for both methods, of course. – Jon Skeet Jul 25 '13 at 21:27
1

Create wrapper for Comparison such as this one:

public class ComparisonWrapper<T> : IComparer<T>
{
    private Comparison<T> comparison;
    public ComparisonWrapper(Comparison<T> comparison)
    {
        this.comparison = comparison;
    }

    public int Compare(T x, T y)
    {
        return comparison(x, y);
    }
}
MagnatLU
  • 5,967
  • 1
  • 22
  • 17
0

Here's an extension on Jon's answer that takes a lambda expression.

public static class ListExtensions
{
    public static int BinarySearch<T>(this List<T> list, T item, Func<T, T, int> compare)
    {
        return list.BinarySearch(item, new ComparisonComparer<T>(compare));
    }
}

public class ComparisonComparer<T> : IComparer<T>
{
    private readonly Comparison<T> comparison;

    public ComparisonComparer(Func<T, T, int> compare)
    {
        if (compare == null)
        {
            throw new ArgumentNullException("comparison");
        }
        comparison = new Comparison<T>(compare);
    }

    public int Compare(T x, T y)
    {
        return comparison(x, y);
    }
}
Daniel Imms
  • 47,944
  • 19
  • 150
  • 166