假设我们有一个排序列表:
lst = [1,3,4,89,456,543] # a long one
我们想要做的是找到列表中小于mx
的元素数。
易:
n = len([x for x in lst if x < mx])
或与发电机:
n = sum(1 for x in lst if x < mx)
我认为第二种方法应该稍快一些,但是,问题仍然是我们在早期停止时会浏览列表的所有元素。它没有使用列表已排序的事实。
是的,我可以用循环来做到这一点:
s = 0
for x in lst:
if x >= mx:
break
s += 1
但是,我觉得必须有一个更好(更短和/或更快)的方法来做同样的事情,可能有一些发电机或外部模块功能?
答案 0 :(得分:9)
我们可以通过二进制搜索做得更好,我们可以在bisect
模块中轻松实现:
import bisect
n = bisect.bisect_left(lst, mx)
这需要lst
长度的对数时间,而早期终止的线性搜索在n
中是线性的。这通常会更快。
如果您想使用线性搜索,takewhile
中的itertools
函数可以提前停止迭代:
import itertools
n = sum(1 for _ in itertools.takewhile(lambda x: x < mx, lst))
答案 1 :(得分:0)
我正在尝试使用二进制搜索来解决:
#!/usr/bin/python
lst = range(12, 100)
mx = 30
def binary_search(data, target, low, high):
if low > high:
return False
else:
mid = (low + high) // 2
if target == data[mid]:
return mid
elif target < data[mid]:
return binary_search(data, target, low, (mid - 1))
else:
return binary_search(data, target, mid + 1, high)
if __name__ == '__main__':
index = binary_search(lst, mx, 0, len(lst) + 1)
print 'Count: %d' % len(lst[:index])
print lst[:index]
输出:
Count : 18
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]