递归递减列表1

Lou*_*bot 13 python recursion

非常快速简单的家庭作业问题.我运行正常,但我认为有更好的
方法.一种更加Pythonic的方式.
这是我的代码递归递减列表的每个元素1.

l = range(30)  
def recurseDecrMap(l, x = []):  
    if len(l) == 0:  
        return []  
    else:  
        x.append(l[0] -1)  
    recurseDecrMap(l[1:], x)  
    return x  
Run Code Online (Sandbox Code Playgroud)

所以感谢任何输入.我正在努力学习做更好的递归.无法
掌握它的诀窍.

Ela*_*zar 25

可能不那么 pythonic,但有:

def recurseDecrMap(l):
    return [l[0]-1] + recurseDecrMap(l[1:]) if l else []
Run Code Online (Sandbox Code Playgroud)

  • 这不是pythonic!会+1如果我还有选票 (6认同)

A. *_*das 14

你只能使用一个参数,在我看来它更简单:

def recurseDecrMap(l):  
    if not l:  
        return []  
    else:
        return [l[0]-1] + recurseDecrMap(l[1:])
Run Code Online (Sandbox Code Playgroud)

但正如@jamylak指出的那样,该算法的复杂性为O(N ^ 2),因为l[1:]创建了一个新列表,其中包含对列表中其余项的引用.

如果你需要效率,我建议你使用列表理解(Haidro的答案),但我想如果你只是为了学习目的,它不是一个优先事项.

  • 在检查空列表时,我建议做`if not l`而不是`if len(l)== 0`. (4认同)
  • @Elazar [PEP8](http://www.python.org/dev/peps/pep-0008/#programming-recommendations)说"使用空序列为假的事实" (4认同)

asm*_*rer 9

对于它的价值,这是一种了解递归的可怕方法,因为你正在使用它来做一些本身不具有递归性的东西.如果你的老师真的要求你写一个程序,[1, 2, 3, 4] 递归递减列表的元素,那么他/她就会感到羞耻.

正如Haidro所说,解决这个问题的最Pythonic方法是使用列表理解迭代列表

[i - 1 for i in l]
Run Code Online (Sandbox Code Playgroud)

作为一个循环,这是

def decr(l):
    a = []
    for i in l:
        a.append(i - 1)
    return a
Run Code Online (Sandbox Code Playgroud)

如果要在任意深度级别解决相同问题,则递归很有用.例如,假设您有类似的东西,[1, [2, 3], [[4], 5]]并且您希望将每个数字减1,同时保持列表结构.在这种情况下,递归解决方案将使用基本情况的迭代解决方案,并为递归情况调用自身.

def decr_recursive(l):
    a = []
    for i in l:
        if isinstance(i, list):
            a.append(decr_recursive(i))
        else:
            a.append(i - 1)
    return a
Run Code Online (Sandbox Code Playgroud)

如果您想要支持的不仅仅是列表或整数,这可以很容易地修改.

>>> decr([1, [2, 3], [[4], 5]])
[0, [1, 2], [[3], 4]]
Run Code Online (Sandbox Code Playgroud)

是一种在不使用递归的情况下很难解决的问题,但很容易用它来解决.你要问的是在没有递归的情况下很容易解决的问题(这只是为了上帝而在列表上进行的简单迭代),但有些难以用它来解决.

你应该避免在Python中递归的一些原因

  • 它更难阅读.比较[i - 1 for i in l],甚至是显式循环,比如

    def decr(l):
        if not l:
            return []
        return [l[0] - 1] + decr(l[:1])
    
    Run Code Online (Sandbox Code Playgroud)
  • 在Python中调用函数可能很昂贵.我在电脑上和Ashwini Chaudhary大致相同.但是[i - 1 for i in range(10**4)]我的电脑需要559μs.这比最快的递归方法快三个数量级.

  • 除非您将递归限制设置得更高,否则递归函数不会超过1000次调用.你可能已经注意到了sys.setrecursionlimit(10**5)Ashwini Chaudhary的回答.这是必要的,因为没有它,每次调用都会导致RuntimeError: maximum recursion depth exceeded跟随一个巨大的追溯.但即便如此,更大的列表仍然会导致递归限制.根据文档,每个操作系统都有一个上限,将其设置得太高可能会导致崩溃.

  • 递归函数更难调试.它们不仅会使用来自同一函数的数百个调用来污染堆栈跟踪,但它们在概念上更难以遵循,因为同一函数的相同部分以不同的方式使用,具体取决于您在堆栈中的哪个级别人类自然的思维方式是迭代的.我们一次做一件事.我们自己的大脑"堆栈"只有几层深,所以我们很难以递归方式解决问题,比如"让我开始解决问题,但在我完成之前,让我解决另一个问题,然后当我完成后,我将完成原来的问题.在较小的问题中,我可能会做同样的事情,所以在我完成之前我会得到几个等级." 这就是为什么你走进厨房拿笔,然后你看到一个糖果棒开始吃它,当你完成后,你忘记了笔.你"递归"了一个级别,从笔问题到直板问题,​​你的心理堆栈太深了(只有两个级别,但这就足够了).如果你反而抓住了糖果棒,但是在你打开它并开始吃它之前,还找到了笔(我能想出的最佳迭代方法),你可以做到这两点而不会忘记.解决程序问题的方式应该与解决问题的方式完全相同,因为这是了解代码执行情况的唯一方法.Python是一种非常好的语言,因为它的高级接口让你可以做到这一点(至少比在低级语言中更常见).用这个事实!


Ela*_*zar 6

这是最糟糕的方式 - 使用Fixed Point Combinator:

Y = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))
recurseDecrMap = Y(lambda f: lambda l: [l[0]-1] + f(l[1:]) if l else [])
Run Code Online (Sandbox Code Playgroud)