【问题标题】:How to get the nearest key to a specified number in a dictionary?如何获取字典中指定数字的最近键?
【发布时间】:2016-03-20 01:31:31
【问题描述】:

我有一个 Excel 函数,我正在尝试将其转换为 C# 等效代码。函数(在Excel中)如下:

WorksheetFunction.VLookup(number, Range("numberDictionary"), 2, True)

这个函数的本质是......

假设存在字典,定义如下:

Number | Value
1      | 2
3      | 8
9      | 1

并假设我的参数“数字”等于 2

我希望返回的值是 8,因为查找函数会将我的输入数字 2 向上舍入到范围 (3) 中最接近的数字,然后返回相关的值。

谁能告诉我如何在 C# 代码中实现同样的功能?假设使用Dictionary<int, int>()

在此先感谢

伊恩

【问题讨论】:

  • @HimBromBeere 在这种情况下,该函数将向上舍入到最近的键
  • 您可以使用有序集合和二分搜索算法。如果您坚持使用 O(n) 的字典,因为您必须查看所有键。
  • 如果number 是 10(基本上是高于最高键的数字)会发生什么?

标签: c# math dictionary


【解决方案1】:

如果您坚持使用字典,您可以使用以下 LINQ 查询:

Dictionary<int, int> dictionary = new Dictionary<int, int>() { 
    {1,2} ,{3,8} ,{9,1} 
};

int searchKey = 2;
int value;

if (dictionary.ContainsKey(searchKey))
    value = dictionary[searchKey];
else
{
    int nearestKey = dictionary.Keys
        .Select(i => new { Value = i, Diff = Math.Abs(i - searchKey) })
        .OrderBy(x => x.Diff)
        .ThenBy(x => x.Value > searchKey ? 0 : 1) // in case of ties you want the higher number
        .Select(x => x.Value)
        .First();
    value = dictionary[nearestKey];
}

这将是O(n),因为您必须查看所有键。如果你可以使用有序集合和二分搜索算法,那就是O(log n)。所以你可以使用SortedDictionary&lt;TKey, TValue&gt;SortedList&lt;TKey, TValue&gt;Differences

使用SortedList,您可以使用this extension method。那么就很简单了:

int index = dictionary.FindFirstIndexGreaterThanOrEqualTo(2);
int value = dictionary[dictionary.Keys[index]];

【讨论】:

  • 您的方法是 O(N*log(N)),因为您对整个集合进行排序只是为了搜索一个值。
  • @Servy:你指的是什么方法?我的第二种方法假定 OP 首先使用SortedList。我也不知道性能是 OP 的关键标准。
  • 我指的是原始版本,您建议对字典的全部内容进行排序以找到一个值。
  • @Servy:您在我编辑答案 5 分钟后发表了评论。随意提供更有效的方法。我确定有一个。
【解决方案2】:
        var input = 2;
        var dictionary = new Dictionary<int, int> { { 1, 2 }, { 3, 8 }, { 9, 1 } };

        var smallestDifference = int.MaxValue;
        var keys = new List<int>();

        if (dictionary.ContainsKey(input))
        {
            return dictionary[input];
        }

        foreach (var entry in dictionary)
        {
            var difference = entry.Key - input;
            if (difference < smallestDifference)
            {
                smallestDifference = difference;
                keys = new List<int>() { entry.Key };
            }
            else if (difference == smallestDifference)
            {
                keys.Add(entry.Key);
            }
        }

        var candidates = dictionary.Where(x => x.Key == smallestDifference).ToList();
        if ( candidates.Count == 1)
        {
            return candidates.SingleOrDefault();
        }
        return candidates.SingleOrDefault(y => y > input);

【讨论】:

    【解决方案3】:

    您可以利用IDictionary&lt;TKey, TValue&gt;Keys 属性:

    var dictionary = new Dictionary<int, int> { { 1, 2 }, { 3, 8 }, { 9, 1 } };
    var key = dictionary.Keys.Where(a => a >= 2).OrderBy(a => a).First();
    var value = dictionary[key];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-08
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      相关资源
      最近更新 更多