Recently, I learned that the Sorted Dictionary class implements binary search over the keys, and I wanted to use this to my advantage. I am making a piecewise linear function class that represents a collection of lines over a bunch of intervals.
I defined an Interval class like this:
public class Interval : ICloneable, IComparable, IComparable<Interval>
{
public Interval()
{
}
public Interval(double start, double end)
{
Start = start;
End = end;
}
// Properties
public double Start { get; set; } = double.NaN;
public double End { get; set; } = double.NaN;
public double Span => End - Start;
// Methods
public object Clone() => MemberwiseClone();
public int CompareTo(object obj)
{
return Start.CompareTo(obj);
}
public int CompareTo([AllowNull] Interval other)
{
if (Start < other.Start)
{
return -1;
}
else if (Start > other.Start)
{
return 1;
}
else
{
return 0;
}
}
public bool Contains(double x) => Start <= x && x <= End;
public override string ToString() => $"[{Start}, {End}]";
}
And the SortedDictionary in question works like this in the piecewise function class:
public class PiecewiseLinearFunction : ICloneable
{
...
// The dictionary
public SortedDictionary<Interval, Line2D> Functions { get; set; } = new SortedDictionary<Interval, Line2D>(); // Where Line2D is just a class that contains a function definition for a line
// Methods
public Interval FindInterval(double x)
=> Functions.Keys.Where(interval => interval.Contains(x)).FirstOrDefault();
public double Solve(double x)
{
var interval = FindInterval(x);
if (interval != null && Functions.ContainsKey(interval))
{
return Functions[interval].Solve(x);
}
else
{
return double.NaN;
}
}
}
So as you can see, the PiecewiseLinearFunction.FindInterval(double x) method linearly searches through the dictionary's keys in order to find the interval that contains (or doesn't contain) x, which can be used for binary look-up, but that obviously defeats the purpose of doing the binary look-up at all.
I was wondering if I could somehow make the dictionary look up the double x value instead, and do a binary search over the intervals while checking if Interval.Contains(double x) is true or false to decide if there is a valid interval (key) and a corresponding line that can be used to get the function value at x.
In other words, is there a way to search with a predicate, something like FindInterval(double x) => Functions.Keys.FindBinary(i => i.Contains(x)).