递归并返回以查找值索引

时间:2018-07-24 09:50:24

标签: python python-3.x recursion

因此,我在一张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?

1 个答案:

答案 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),因为验证与实际索引搜索分开,因此不会影响索引总和。