Python:确定词典中数字最接近匹配的优雅方法

时间:2012-07-01 17:34:43

标签: python

我有一个将id(整数)映射到数字(double)的字典结构。这些数字实际上是一个项目的权重。

我正在编写一个函数,允许我获取给定权重的id(如果在dict中找到权重,否则,它将返回下一个最接近的 id (即最接近的)重量。

这是我到目前为止所做的:

def getBucketIdByValue(bucketed_items_dict, value):
    sorted_keys = sorted(bucketed_items_dict.keys())
    threshold = abs(bucketed_items_dict[sorted_keys[-2]] -bucketed_items_dict[sorted_keys[-1]]) # determine gap size between numbers

    # create a small dict containing likely candidates
    temp = dict([(x - value),x] for x in bucketed_items_dict.values() if abs(x - value) <= threshold)
    print 'DEBUG: Deviations list: ', temp.keys()
    smallest_deviation = min(temp.keys()) if value >= 0 else max(temp.keys()) # Not sure about this ?
    smallest_deviation_key = temp[smallest_deviation]
    print 'DEBUG: found bucketed item key:',smallest_deviation_key
    return smallest_deviation_key

我不确定逻辑是否正确(尤其是我获得最小的deviatioon)。无论如何,即使逻辑是正确的,这似乎是一种过于复杂的做事方式。有没有更优雅/ pythonic的方式这样做?

在我的脑海中,我认为一种更加pythonic /更优雅的方式就是将自定义函数传递给min函数 - 不知道是否可能......

[[更新]]

我正在运行Python 2.6.5

4 个答案:

答案 0 :(得分:4)

尝试按重量与目标值的距离对项目进行排序:

from operator import itemgetter
distances = ((k, abs(v - value)) for k, v in bucketed_items_dict.items())
return min(distances, key=itemgetter(1))[0]

或者使用lambda函数而不是itemgetter:

distances = ((k, abs(v - value)) for k, v in bucketed_items_dict.items())
return min(distances, key=lambda x:x[1])[0]

答案 1 :(得分:3)

def getBucketIdByValue(bucket, value):
    distances = [( id , abs( number - value ) ) for id , number in bucket.items()]
    swapped = [( distance , id ) for id , distance in distances]
    minimum = min ( swapped )
    return minimum[1]

或简而言之:

def getBucketIdByValue(bucket, value):
    return min((abs(number-value),id) for id,number in bucket.items())[1]

此函数使用存储桶创建id / number对,然后创建一个距离/ id对的迭代器,然后得到它的第一个最小对,最后提取该对的id并返回它。

距离定义为数字与所寻求值之差的绝对值。

最小值定义为距离最短的对。如果还有更多,则返回具有最低id的对。

答案 2 :(得分:2)

您可以使用排序键中的bisect找到最接近重量的索引:

import bisect

def bisect_weight(sorted_keys, value):
    index = bisect.bisect(sorted_keys, value)
    # edge cases
    if index == 0: return sorted_keys[0]
    if index == len(sorted_keys): return sorted_keys[index - 1]
    minor_weight = sorted_keys[index - 1]
    greater_weight = sorted_keys[index]

    return minor_weight if abs(minor_weight - value) < abs(greater_weight - value) else greater_weight

这样你只需要检查2个重量并找到最好的重量。排序和二进制搜索可能比计算所有权重更快并找到最佳权重。

答案 3 :(得分:1)

我还会考虑bisect模块。