您可以简单地使用二进制搜索:
def binary_f(f,list):
frm = 0
to = len(list)
while frm < to:
mid = (frm+to)>>1
if f(list[mid]):
to = mid
else:
frm = mid+1
return frm
它将返回is的第一个索引i
。bool(f(list[i]))
True
当然,该函数假定f
on 的地图具有list
以下形式:
f(list) == [False,False,...,False,True,True,...,True]
如果不是这种情况,它通常会找到一个交换,但哪个交换是相当不确定的。
说f
的只是“版本是2或更高”所以lambda v:v >= '2'
,然后它会返回:
>>> binary_f(lambda v:v >= '2',['1.0', '1.14', '2.3', '3.1', '4'])
2
所以索引2
。如果整个列表将返回False
对象,它将 **return len(list)
。由于它“假定”列表之外的元素将被评估为True
:
>>> binary_f(lambda v:v >= '4.2',['1.0', '1.14', '2.3', '3.1', '4'])
5
当然在你的例子f
中是works
.
实验:
>>> binary_f(lambda v:v >= '2',['1.0', '1.14', '2.3', '3.1', '4'])
2
>>> binary_f(lambda v:v >= '0',['1.0', '1.14', '2.3', '3.1', '4'])
0
>>> binary_f(lambda v:v >= '1',['1.0', '1.14', '2.3', '3.1', '4'])
0
>>> binary_f(lambda v:v >= '1.13',['1.0', '1.14', '2.3', '3.1', '4'])
1
>>> binary_f(lambda v:v >= '2.4',['1.0', '1.14', '2.3', '3.1', '4'])
3
>>> binary_f(lambda v:v >= '3',['1.0', '1.14', '2.3', '3.1', '4'])
3
>>> binary_f(lambda v:v >= '3.2',['1.0', '1.14', '2.3', '3.1', '4'])
4
>>> binary_f(lambda v:v >= '4.2',['1.0', '1.14', '2.3', '3.1', '4'])
5
(我在这里当然做了一个非常便宜的版本检查,但它当然适用于更复杂的谓词)。
由于这是二分搜索,它将在O(log n)中运行,其中n是列表中的项目数,而线性搜索可能会导致O(n)检查(这通常更昂贵)。
编辑:如果列表包含两个值并且您想要找到交换,您可以简单地首先计算 index 的值0
:
val0 = f(list[0])
然后提供binary_f
:
binary_f(lambda v:works(v) != val0,list)
或将其放入一个不错的功能中:
def binary_f_val(f,list):
val0 = f(list[0])
return binary_f(lambda x:f(x) != val0,list)