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))
.