You can simply use binary search :
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
It will return the first index i for which bool(f(list[i])) is True .
Of course, the function assumes that the mapping f to list has the form:
f(list) == [False,False,...,False,True,True,...,True]
If this is not the case, it will usually find a swap, but which is more like undefined.
Say f just βversion 2 or higher,β so lambda v:v >= '2' , then it will return:
>>> binary_f(lambda v:v >= '2',['1.0', '1.14', '2.3', '3.1', '4']) 2
So index 2 . If the whole list returns with False objects, it will return len(list) . Since it "accepts", an item located outside the list will be evaluated as True :
>>> binary_f(lambda v:v >= '4.2',['1.0', '1.14', '2.3', '3.1', '4']) 5
Of course, in your example f there are works .
Experiments
>>> 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
(I, of course, did a very cheap version check here, but, of course, this works for more complex predicates).
Since this is a binary search, it will work in O (log n) with n number of items in the list, while a linear search can result in O (n) checking (which is usually more expensive).
EDIT : if the list contains two values ββand you want to find swap, you can simply calculate the value for index 0 :
val0 = f(list[0])
and then specify binary_f :
binary_f(lambda v:works(v) != val0,list)
Or add it to a nice function:
def binary_f_val(f,list): val0 = f(list[0]) return binary_f(lambda x:f(x) != val0,list)