What .NET dictionary supports a “find nearest key” operation?

后端 未结 8 691
[愿得一人]
[愿得一人] 2020-12-18 23:08

I\'m converting some C++ code to C# and it calls std::map::lower_bound(k) to find an entry in the map whose key is equal to or greater than k. However, I don\'t see any way

相关标签:
8条回答
  • 2020-12-18 23:56

    You can try the code i wrote below. it using binary search, therefore assuming the list/array is pre-sorted.

    public static class ListExtensions
    {
        public static int GetAtMostIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer)
        {
            return GetAtMostIndex(list, value, comparer, 0, list.Count);
        }
    
        public static int GetAtLeastIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer)
        {
            return GetAtLeastIndex(list, value, comparer, 0, list.Count);
        }
    
        public static int GetAtMostIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer, int index, int count)
        {
            if (count == 0)
            {
                return -1;
            }
    
            int startIndex = index;
            int endIndex = index + count - 1;
            int middleIndex = 0;
            int compareResult = -1;
    
            while (startIndex < endIndex)
            {
                middleIndex = (startIndex + endIndex) >> 1; //  / 2
                compareResult = comparer.Invoke(list[middleIndex], value);
    
                if (compareResult > 0)
                {
                    endIndex = middleIndex - 1;
                }
                else if (compareResult < 0)
                {
                    startIndex = middleIndex + 1;
                }
                else
                {
                    return middleIndex;
                }
            }
    
            if (startIndex == endIndex)
            {
                compareResult = comparer.Invoke(list[startIndex], value);
    
                if (compareResult <= 0)
                {
                    return startIndex;
                }
                else
                {
                    int returnIndex = startIndex - 1;
    
                    if (returnIndex < index)
                    {
                        return -1;
                    }
                    else
                    {
                        return returnIndex;
                    }
                }
            }
            else
            {
                //todo: test
                return startIndex - 1;
            }
        }
    
        public static int GetAtLeastIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer, int index, int count)
        {
            if (count == 0)
            {
                return -1;
            }
    
            int startIndex = index;
            int endIndex = index + count - 1;
            int middleIndex = 0;
            int compareResult = -1;
    
            while (startIndex < endIndex)
            {
                middleIndex = (startIndex + endIndex) >> 1; //  / 2
                compareResult = comparer.Invoke(list[middleIndex], value);
    
                if (compareResult > 0)
                {
                    endIndex = middleIndex - 1;
                }
                else if (compareResult < 0)
                {
                    startIndex = middleIndex + 1;
                }
                else
                {
                    return middleIndex;
                }
            }
    
            if (startIndex == endIndex)
            {
                compareResult = comparer.Invoke(list[startIndex], value);
    
                if (compareResult >= 0)
                {
                    return startIndex;
                }
                else
                {
                    int returnIndex = startIndex + 1;
    
                    if (returnIndex >= index + count)
                    {
                        return -1;
                    }
                    else
                    {
                        return returnIndex;
                    }
                }
            }
            else
            {
                return endIndex + 1;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-18 23:59

    find nearest to K:

    dict.Keys.Where(i => i >= K).OrderBy(i => i).First();
    

    or much faster:

    public int? GetNearestKey(dict, K) 
    {
        int? lowerK = null;
        foreach (int key in dict.Keys)
        {
            if (key == K) 
            {
                lowerK = K;
                break; 
            }
            else if (key >= K && (!lowerK.HasValue || key < lowerK))
            {
                lowerK = key;
            }
        }
        return lowerK;
    }
    
    0 讨论(0)
提交回复
热议问题