What is the fastest way to get all the keys between 2 keys in a SortedList?

前端 未结 3 1921
心在旅途
心在旅途 2021-01-18 11:11

Given a populated SortedList. I would like to get all the keys (or their index range, what should be a closed int interval (mis

3条回答
  •  执念已碎
    2021-01-18 11:53

    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.

提交回复
热议问题