【问题标题】:In a python list which is sorted, find the closest value to target value and its index in the list在已排序的python列表中,找到最接近目标值的值及其在列表中的索引
【发布时间】:2019-10-13 13:48:34
【问题描述】:

我正在尝试在 python 的排序列表中获取最接近的值及其索引。

在 MATLAB 中,这可以通过:

[closest_val,index] = min(abs(array - target))

我想知道是否有类似的方式可以在 python 中实现。

我看到过一个或另一个的帖子,但我没有看到两者一起完成。

Link 在列表帖子中查找最接近的值。

【问题讨论】:

  • @wovano:不是骗子,因为 OP 特别指出它是相似的,但明确指出这是针对 排序的列表。
  • 链接中接受的答案实际上返回最接近的值及其索引。这个答案不能接受吗?该解决方案也适用于排序列表。如果还有其他要求(比如性能?),我认为应该将这些添加到这个问题中以使其与众不同。
  • @wovano:正如我自己的回答所引用的那样,对于这些情况,这个答案并不理想。或者,如果一个类比会有所帮助,“你怎么吃汤”不是“你怎么喝柠檬水”的骗局,尽管后者的回答“通过吸管”也适用于汤(人们希望得到“用勺子”,更适合汤)。
  • 我知道有人可能想要一个更好或最优的解决方案,但此时的问题只表明“我看到过一个或另一个的帖子,但我没有看到两者一起完成。”这似乎不是真的。我建议应该使用其他标准来改进问题,以使问题与众不同。

标签: python python-3.x list


【解决方案1】:

这是一个选项:

lst = [
    13.09409,
    12.18347,
    11.33447,
    10.32184,
    9.544922,
    8.813385,
]

target = 11.5

res = min(enumerate(lst), key=lambda x: abs(target - x[1]))
# (2, 11.33447)

enumerateindex, value 对的形式遍历您的列表。 min 方法的 key 告诉它只考虑 value

注意python从0开始索引;据我记得,matlab 在1。如果你想要同样的行为:

res = min(enumerate(lst, start=1), key=lambda x: abs(target - x[1]))
# (3, 11.33447)

【讨论】:

    【解决方案2】:

    bisect 未在链接问题中使用,因为列表未排序。在这里,我们没有同样的问题,我们可以使用bisect,因为它提供的速度:

    import bisect
    
    def find_closest_index(a, x):
        i = bisect.bisect_left(a, x)
        if i >= len(a):
            i = len(a) - 1
        elif i and a[i] - x > x - a[i - 1]:
            i = i - 1
        return (i, a[i])
    
    find_closest_index([1, 2, 3, 7, 10, 11], 0)   # => 0, 1
    find_closest_index([1, 2, 3, 7, 10, 11], 7)   # => 3, 7
    find_closest_index([1, 2, 3, 7, 10, 11], 8)   # => 3, 7
    find_closest_index([1, 2, 3, 7, 10, 11], 9)   # => 4, 10
    find_closest_index([1, 2, 3, 7, 10, 11], 12)  # => 5, 11
    

    编辑:如果是降序数组:

    def bisect_left_rev(a, x, lo=0, hi=None):
        if lo < 0:
            raise ValueError('lo must be non-negative')
        if hi is None:
            hi = len(a)
        while lo < hi:
            mid = (lo+hi)//2
            if a[mid] > x: lo = mid+1
            else: hi = mid
        return lo
    
    def find_closest_index_rev(a, x):
        i = bisect_left_rev(a, x)
        if i >= len(a):
            i = len(a) - 1
        elif i and a[i] - x < x - a[i - 1]:
            i = i - 1
        return (i, a[i])
    
    find_closest_index_rev([11, 10, 7, 3, 2, 1], 0)   # => 5, 1
    find_closest_index_rev([11, 10, 7, 3, 2, 1], 7)   # => 2, 7
    find_closest_index_rev([11, 10, 7, 3, 2, 1], 8)   # => 2, 7
    find_closest_index_rev([11, 10, 7, 3, 2, 1], 9)   # => 1, 10
    find_closest_index_rev([11, 10, 7, 3, 2, 1], 12)  # => 0, 11
    

    【讨论】:

    • 这个方法比@hiro 贴的方法快吗?我可能会在包含大约 1000 - 2000 个条目的列表中执行此操作。
    • 在我的计算机上,使用我的方法在大小为 2000 的数组上搜索随机数的速度平均提高了 37 倍(在 100 个样本上)。在更大的阵列上它会更快。原因是bisect 完全在C 中工作,而Hiro 的方法很大程度上依赖于Python; bisectO(log N),而 Hiro 是 O(N)
    • 是的,如果您的列表开始排序(并且速度是一个问题),我强烈建议您使用bisect!好一个! +1
    • 它似乎不适用于负数。我使用它的列表之一以正浮点数开始,但它们的值减小并变为负数。
    • 请准确。我看不到错误,我不会测试所有负数的所有组合。与其说“不起作用”,不如举个例子说明您尝试过的结果错误的事情?
    猜你喜欢
    • 2020-03-25
    • 2015-07-26
    • 2012-03-31
    • 2015-10-24
    • 2014-12-27
    • 1970-01-01
    • 2011-09-05
    • 2018-01-29
    • 2021-11-20
    相关资源
    最近更新 更多