Given a populated SortedList
. I would like to get all the keys (or their index range, what should be a closed int interval (mis
I wondered why SortedList
doesn't provide a BinarySearch
when it's already sorted by the keys. It also uses the method itself(f.e. in IndexOf
), but the array used is a private field.
So i've tried to create an extension method for this, have a look:
public static class SortedListExtensions
{
public static int BinarySearch(this SortedList sortedList, TKey keyToFind, IComparer comparer = null)
{
// need to create an array because SortedList.keys is a private array
var keys = sortedList.Keys;
TKey[] keyArray = new TKey[keys.Count];
for (int i = 0; i < keyArray.Length; i++)
keyArray[i] = keys[i];
if(comparer == null) comparer = Comparer.Default;
int index = Array.BinarySearch(keyArray, keyToFind, comparer);
return index;
}
public static IEnumerable GetKeyRangeBetween(this SortedList sortedList, TKey low, TKey high, IComparer comparer = null)
{
int lowIndex = sortedList.BinarySearch(low, comparer);
if (lowIndex < 0)
{
// list doesn't contain the key, find nearest behind
// If not found, BinarySearch returns the complement of the index
lowIndex = ~lowIndex;
}
int highIndex = sortedList.BinarySearch(high, comparer);
if (highIndex < 0)
{
// list doesn't contain the key, find nearest before
// If not found, BinarySearch returns the complement of the index
highIndex = ~highIndex - 1;
}
var keys = sortedList.Keys;
for (int i = lowIndex; i < highIndex; i++)
{
yield return keys[i];
}
}
}
Create a sample SortedList
:
DateTime start = DateTime.Today.AddDays(-50);
var sortedList = new SortedList();
for(int i = 0; i < 50; i+=2)
{
var dt = start.AddDays(i);
sortedList.Add(dt, string.Format("Date #{0}: {1}", i, dt.ToShortDateString()));
}
DateTime low = start.AddDays(1); // is not in the SortedList which contains only every second day
DateTime high = start.AddDays(10);
Now you can use the extension method above to get the range of keys between a low- and high-key:
IEnumerable dateRange = sortedList.GetKeyRangeBetween(low, high).ToList();
Result:
04/04/2014
04/06/2014
04/08/2014
04/10/2014
Note that this is built from scratch and not really tested, but it could give you an idea anyway.