在排序列表中查找下一个较低的项目

时间:2010-04-07 09:10:33

标签: python

假设我有一个Floats排序列表。现在我想获得给定值的下一个较低项的索引。通常的for-loop aprroach具有O(n)的复杂性。由于列表已排序,因此必须有一种方法可以使用O(log n)获取索引。

我的O(n)方法:

index=0
for i,value in enumerate(mylist):
    if value>compareValue:
        index=i-1

是否有用于解决O(log n)中的问题的数据类型?

最好的问候 塞巴斯蒂安

7 个答案:

答案 0 :(得分:15)

bisect怎么样?

>>> import bisect
>>> float_list = [1.0, 1.3, 2.3, 4.5]
>>> i = bisect.bisect_left(float_list, 2.5)
>>> index = i - 1
>>> index
2

您可能必须单独处理搜索值小于或等于列表中最低/最左侧值的情况(在这种情况下为index == -1)。

根据您在平等的情况下希望拥有的索引,您可能不得不使用bisect_right

答案 1 :(得分:10)

您可以对数组/列表执行二进制搜索以获取您正在查找的对象的索引,并获取其下方的索引以获取较低的条目(假设实际上存在较低的条目!)。< / p>

请参阅:Binary search (bisection) in Python

comparing floating point numbers要求平等!

答案 2 :(得分:2)

使用bisect模块。功能

bisect.bisect_left(mylist, compareValue)

返回列表中项目的正确插入点以维护排序顺序。

答案 3 :(得分:2)

import bisect

def next_lower_value(values_list, input_value):
    index= bisect.bisect_left(values_list, input_value)
    if index == 0: # there's not a "next lower value"
        raise NotImplementedError # you must decide what to do here
    else:
        return values_list[index - 1]

>>> l= [11, 15, 23, 28, 45, 63, 94]
>>> next_lower_value(l, 64)
63
>>> next_lower_value(l, 63)
45
>>> next_lower_value(l, 1000)
94
>>> next_lower_value(l, 1)
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    next_lower_value(l, 1)
  File "<pyshell#26>", line 4, in next_lower_value
    raise NotImplementedError # you must decide what to do here
NotImplementedError

由于您请求索引而不是下一个较低的值,请将函数next_lower_value更改为返回index - 1而不是values_list[index - 1]

答案 4 :(得分:1)

回答关于数据类型的部分问题:在一般意义上,最适合在O(log n)时间内查找事物的数据类型(在插入和删除时保持O(1)性能!)是二叉树。您可以通过做出一系列左右决定来查找其中的内容,这非常类似于您在线性列表中进行二进制搜索的方式,但(IMO)在概念上更直观。

也就是说,从我对Python的了解很少,二叉树似乎不在语言的标准库中。对于您的应用程序,仅为此目的包含实现可能没有任何好处。

最后,排序列表中的二叉树和二进制搜索将允许您将搜索缩短一步:没有必要搜索关键项,然后返回其前一个。相反,在每个比较步骤中,如果遇到键值,就好像它太大了。这将导致您的搜索结束下一个较小的值。仔细完成,这也可能有助于bart提到的“几乎相等的浮点值”问题。

答案 5 :(得分:1)

如果我正确读取此项,则下一个较低的项目是列表中第一个小于或等于x的项目。 bisect documentation for searching sorted lists提供了此功能:

def find_le(a, x):
    'Find rightmost value less than or equal to x'
    i = bisect_right(a, x)
    if i:
        return a[i-1]
    raise ValueError

答案 6 :(得分:0)

def lower_bound(arr, x):
    left = 0
    right = len(arr)-1
    mid = -1
    if(arr[left] > x):
        return mid
    while(left <= right):
        mid = int(left + (right - left + 1) / 2)
        if(left == right and right == mid):
            return mid
        if(x > arr[mid]):
            left = mid
        elif(x < arr[mid]):
            right = mid - 1
        else:
            return mid
    return mid

如果找到了精确的元素,则此函数返回已排序列表“ arr”中元素的索引,否则返回小于给定数字“ x”的最大元素的索引。如果没有元素小于给定的数字,则返回-1。