因此,我在一张CSE 101幻灯片中遇到了一个运动问题,该问题要求使用递归在列表或字符串中查找值。如果该值在列表或字符串内,则返回与该值匹配的第一个索引位置。我能够解决它,但是我不明白为什么会起作用。这是我的代码:
def rindex(a, pos):
if pos not in a:
return None
elif pos in a:
if a[0] != pos:
return rindex(a[1:], pos) + 1
return 0
具体来说,我不明白为什么
返回0
使我的功能正常工作。为什么返回正确的值而不是0?
答案 0 :(得分:1)
每次在函数中遇到return
时,都会返回结果,并且函数执行将停止。这意味着除非当前切片中的第一个元素等于return 0
,否则当前切片中的pos
存在a
时将不会遇到pos
点返回0
表示不应增加索引。如果不返回它,默认情况下,rindex()
将返回None
,当您尝试在递归链中与+ 1
求和时会产生错误。
话虽这么说,每当您执行if pos not in a:
时,您都在列表a
上进行迭代以寻找pos
,因此您的代码将效率极低(特别是因为您这样做之后在elif
块中再次进行完全相同的搜索,而简单的else
绰绰有余)。您可以将代码重新编写为:
def rindex(a, pos):
if a[0] == pos: # element found, do not increase the index
return 0
return rindex(a[1:], pos) + 1
因此,您只在执行切片操作,而不是每次递归进行两次迭代。这里最大的问题是,如果列表递归到达末尾,如果找不到IndexError
,它将引发pos
。如果您更喜欢返回值而不是异常,则可以捕获该返回值并返回任何种类的值,因此在您的情况下:
def rindex(a, pos):
if a[0] == pos: # element found, do not increase the index
return 0
try:
return rindex(a[1:], pos) + 1
except (IndexError, TypeError): # capture both to propagate
return None
但是,请记住,即使执行列表切片也不是最有效的解决方案,尤其是在涉及内存时。由于Python将名称传递给引用,因此您可以递归遍历整个列表,而几乎没有损失,也可以使用索引递归遍历列表,即:
def rindex(a, pos, loc=0):
if a[loc] == pos:
return loc
return rindex(a, pos, loc+1)
您甚至不必进行递归try .. except
编排即可捕获错误-您可以直接在函数中进行操作(抢先(LBYL风格):
def rindex(a, pos, loc=0):
if len(a) >= loc:
return None
if a[loc] == pos:
return loc
return rindex(a, pos, loc + 1)
或在事实(EAFP样式之后):
def rindex(a, pos, loc=0):
try:
if a[loc] == pos:
return loc
except IndexError:
return None
return rindex(a, pos, loc + 1)
这些还允许您在找不到元素时传递任意索引(即-1
),因为验证与实际索引搜索分开,因此不会影响索引总和。