我不太明白返回的索引。例如,如果givenY
是和空列表,两者都start
将end
是-1。此外,您发布的代码不会处理列表中的重复值。
bisect
您可以使用该模块代替手动编码的二进制搜索。有关详细信息,请参阅 API 文档:
- 蟒蛇 3.3 - 8.6。bisect - 数组二等分算法
- 蟒蛇 2.7.3 - 8.5。bisect - 数组二等分算法
下面是一个返回的实现,start
因此end
具有以下属性:
end-start
等于给定边界之间的元素数。
list[start:end]
返回包含给定边界之间的所有值的切片。
end-start
等于找到的元素数
- 当没有找到值时
start==end
。
代码:
import unittest
from bisect import bisect_left, bisect_right
def find_range(array, a, b):
start = bisect_right(array,a)
end = bisect_left(array,b)
return (start, end)
class TestCase(unittest.TestCase):
Y = [1, 3, 5, 10, 15]
givenY = [3, 4, 5, 6, 7, 8, 9, 10, 11]
def test_empty_array(self):
self.assertEqual( (0, 0), find_range([], 1, 2) )
def test_all_values_larger(self):
self.assertEqual( (0, 0), find_range([4,5,6], 1, 3) )
def test_all_values_larger_or_equal(self):
self.assertEqual( (0, 0), find_range(self.givenY, self.Y[0], self.Y[1]) )
def test_both_endpoints_inside_list(self):
self.assertEqual( (1, 2), find_range(self.givenY, self.Y[1], self.Y[2]))
self.assertEqual( [4], self.givenY[1:2])
def test_2(self):
self.assertEqual( (3, 7), find_range(self.givenY, self.Y[2], self.Y[3]) )
self.assertEqual( [6, 7, 8, 9], self.givenY[3:7])
def test_no_values_larger_or_equal_to_upper_limit(self):
self.assertEqual( (8, 9), find_range(self.givenY, self.Y[3], self.Y[4]) )
self.assertEqual( [11], self.givenY[8:9])
if __name__=="__main__":
unittest.main()
注意:如果需要,返回的开始和结束位置应该很容易调整到您的当前值,只要确保它是一致的。
编辑
据我从给出的示例中可以理解,下面是返回请求值的代码。逻辑在文档字符串中描述find_range()
。保留原始代码,因为恕我直言,在使用 Python 编程时感觉更自然。
import unittest
from bisect import bisect_left, bisect_right
def find_range(array, a, b):
"""Find elements that are greater than a and less than b.
Returns a tuple (start,end) where array[start] is the first
value and array[end] is the last value.
If no value is found, returns start=end=-1.
"""
start = bisect_right(array,a)
end = bisect_left(array,b)
if start==end:
return (-1,-1)
else:
return (start, end-1)
class TestCase(unittest.TestCase):
Y = [1, 3, 5, 10, 15]
givenY = [3, 4, 5, 6, 7, 8, 9, 10, 11]
def test_empty_array(self):
self.assertEqual( (-1, -1), find_range([], 1, 2) )
def test_all_values_larger(self):
self.assertEqual( (-1, -1), find_range([4,5,6], 1, 3) )
def test_all_values_larger_or_equal(self):
self.assertEqual( (-1, -1), find_range(self.givenY, self.Y[0], self.Y[1]) )
def test_both_endpoints_inside_list(self):
self.assertEqual( (1, 1), find_range(self.givenY, self.Y[1], self.Y[2]))
def test_2(self):
self.assertEqual( (3, 6), find_range(self.givenY, self.Y[2], self.Y[3]) )
def test_no_values_larger_or_equal_to_upper_limit(self):
self.assertEqual( (8, 8), find_range(self.givenY, self.Y[3], self.Y[4]) )
def test_sample(self):
self.assertEqual( (3,3), find_range([1,3,5,7], 5, 8) )
self.assertEqual( (3,3), find_range([1,3,5,7], 6, 8) )
if __name__=="__main__":
unittest.main()