Python 查找位于两个值之间的数组元素
那么问题是这样的: 首先,我用Python编写代码。 我有一个排序自然数的数组(Numpy数组,但如果有帮助的话,我可以把它改成一个列表),“givenY”。我想找到并指向第一个和最后一个元素,其中位于两个指定值之间Python 查找位于两个值之间的数组元素,python,arrays,intervals,binary-search,Python,Arrays,Intervals,Binary Search,那么问题是这样的: 首先,我用Python编写代码。 我有一个排序自然数的数组(Numpy数组,但如果有帮助的话,我可以把它改成一个列表),“givenY”。我想找到并指向第一个和最后一个元素,其中位于两个指定值之间a=Y[I]和b=Y[I+1]。我写了代码,但我相信我用了最糟糕的方式之一,我不确定代码是否暂时有效。因此,如果我能得到评论或建议从头开始写,我会很高兴。重要的是,当在Y[i]和Y[i+1]之间没有givenY元素时,会出现许多异常情况(这是通过分配-1来处理的)。我的代码是: 这
a=Y[I]
和b=Y[I+1]
。我写了代码,但我相信我用了最糟糕的方式之一,我不确定代码是否暂时有效。因此,如果我能得到评论或建议从头开始写,我会很高兴。重要的是,当在Y[i]
和Y[i+1]
之间没有givenY元素时,会出现许多异常情况(这是通过分配-1
来处理的)。我的代码是:
这是binSearch的实施:
def binSearch(arr,element):
left=0
right=arr.size;
mid=(left+right)/2
while left<right:
mid=(left+right)/2
if(arr[mid]<element):
left=mid+1;
elif (arr[mid]>element):
right=mid;
else:
return True,mid;
return False,left;
def binSearch(arr,元素):
左=0
右=arr.size;
中间=(左+右)/2
左时,先对列表排序,然后进行线性搜索
删除分号,它们不是必需的,也不是必需的…先对列表排序,然后进行线性搜索
删除分号,它们不需要也不需要…我不太理解返回的索引。例如,如果givenY
为空且列表为空,则start
和end
都将为-1。此外,您发布的代码不会处理列表中的重复值
您可以使用对分
模块代替手工编码的二进制搜索。有关详细信息,请参阅API文档:
下面是一个返回开始
和结束
的实现,以保持以下属性:
end start
等于给定边界之间的元素数
list[start:end]
返回包含给定边界之间所有值的切片
end start
等于找到的元素数
当未找到值时start==end
代码:
注意:如果需要,返回的起始和结束位置应轻松调整为当前值,只需确保一致即可
编辑
下面是返回所请求的值的代码,据我从给出的示例中了解。逻辑在find_range()
docstring中描述。保留原始代码,因为在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()
我不太理解返回的索引。例如,如果givenY
为空且列表为空,则start
和end
都将为-1。此外,您发布的代码不会处理列表中的重复值
您可以使用对分
模块代替手工编码的二进制搜索。有关详细信息,请参阅API文档:
下面是一个返回开始
和结束
的实现,以保持以下属性:
end start
等于给定边界之间的元素数
list[start:end]
返回包含给定边界之间所有值的切片
end start
等于找到的元素数
当未找到值时start==end
代码:
注意:如果需要,返回的起始和结束位置应轻松调整为当前值,只需确保一致即可
编辑
下面是返回所请求的值的代码,据我从给出的示例中了解。逻辑在find_range()
docstring中描述。保留原始代码,因为在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()
谢谢提醒,列表已排序。因此,使用二进制搜索似乎比线性搜索更符合逻辑。我更喜欢分号,它让我想起了C和Java,但感谢您的提及!线性搜索不会比二进制搜索慢吗?谢谢提醒,列表已排序。因此,使用二进制搜索似乎比线性搜索更符合逻辑。我更喜欢分号,它让我想起了C和Java,但感谢您的提及!线性搜索不会比二进制搜索慢吗?请提供示例输入和输出。什么是givenY
,它是一个列表?请提供示例输入和输出。什么是givenY
,它是一个列表?非常感谢您的时间,但此代码不起作用:对于givenY=[1,3,5,7],它应该返回(3,3),但返回(3,4)这甚至超出了界限。正如我前面提到的,当a和b之间没有给定值供以后使用时,我将start=-1设置为。在这种情况下,Y[I]和Y[I+1]的值是多少?请阅读这篇文章,因为我已经清楚地定义了返回值是什么。特别是,我声明数组[start:end]将返回介于边界之间的值。在这种特殊情况下,4不在边界之外,[1,3,5,7][3:4]
将返回[7]
,因为上界指向第一个不包含的元素(类似于C++中的迭代器)。如果您可以指定在不同情况下返回的内容,我将修改代码以处理此问题。它们是整数值,但这并不重要,因为我说过您可以用a和b替换它们。非常感谢,但我希望结束指向间隔中的最后一个元素!我已经在我的文章中写了很多输入和输出(在文章末尾)我想要测试的实际绑定值:)我又添加了一个代码块,我希望它与您最初要求的匹配。基于代码、示例输出和您的评论,我不能完全确定输出是什么。请检查我的docstring,看看它是否符合您的需要。非常感谢您的时间,但此代码不起作用:对于givenY=[1,3,5,7],它应该返回(3,3),但它返回(3,4),甚至超过了界限。正如我前面提到的,当没有givenY va时,我将start=-1设置为
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()
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()