非常快速简单的家庭作业问题。我运行正常,但我认为有一个更好的
这样做的方式。更多的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
非常感谢任何意见。我正在努力学习做更好的递归。遇到麻烦 它的诀窍。
答案 0 :(得分:25)
可能少 pythonic,但有:
def recurseDecrMap(l):
return [l[0]-1] + recurseDecrMap(l[1:]) if l else []
答案 1 :(得分:14)
你只能使用一个参数,在我看来它更简单:
def recurseDecrMap(l):
if not l:
return []
else:
return [l[0]-1] + recurseDecrMap(l[1:])
但正如@jamylak指出的那样,该算法的复杂性为O(N ^ 2),因为l[1:]
创建了一个新列表,其中包含对列表中其余项的引用。
如果您需要效率,我建议您使用列表推导(Haidro's answer),但我认为如果您只是为了学习目的,它不是优先考虑的事项。
答案 2 :(得分:9)
对于它的价值,这是一种了解递归的可怕方法,因为你正在使用它来做一些本身不具有递归性的东西。如果你的老师真的要求你编写一个程序,递减递归列表的元素,如[1, 2, 3, 4]
递归,那么他/她就会感到羞耻。
正如Haidro所说,解决这个问题的最Pythonic方法是使用列表理解迭代列表
[i - 1 for i in l]
作为循环,这是
def decr(l):
a = []
for i in l:
a.append(i - 1)
return a
如果要在深度的任意级别解决相同的问题,递归很有用。例如,假设您有类似[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
如果您想支持的不仅仅是列表或整数,可以轻松修改。
>>> decr([1, [2, 3], [[4], 5]])
[0, [1, 2], [[3], 4]]
这个是一种在不使用递归的情况下很难解决的问题,但很容易用它来解决。你要问的是没有递归就很容易解决的问题(为了上帝的缘故,这只是一个简单的迭代迭代),但有些难以解决。
为什么要避免Python中的递归
阅读起来比较困难。将[i - 1 for i in l]
或甚至显式循环与
def decr(l):
if not l:
return []
return [l[0] - 1] + decr(l[:1])
在Python中调用函数可能很昂贵。我在电脑上和Ashwini Chaudhary大致相同。但[i - 1 for i in range(10**4)]
在我的电脑上需要559μs。这比最快的递归方法快三个数量级。
除非您将递归限制设置得更高,否则递归函数不会超过1000次调用。您可能已经注意到Ashwini Chaudhary的答案中的sys.setrecursionlimit(10**5)
电话。这是必要的,因为没有它,每次调用都会导致RuntimeError: maximum recursion depth exceeded
跟踪一个巨大的追溯。但即便如此,更大的列表仍然会导致递归限制。根据{{3}},每个操作系统都有一个上限,设置得太高会导致崩溃。
递归函数更难调试。它们不仅会使用来自同一函数的数百个调用来污染堆栈跟踪,但它们在概念上更难以遵循,因为同一函数的相同部分以不同的方式使用,具体取决于您在堆栈中的哪个级别人类自然的思维方式是迭代的。我们一次做一件事。我们自己的大脑“堆栈”只有几层深,所以我们很难以递归方式解决问题,比如“让我开始解决问题,但在我完成之前,让我解决另一个问题,然后当我完成后,我将完成原来的问题。在较小的问题中,我可能会做同样的事情,所以在我完成之前我会得到几个等级。“这就是为什么你走进厨房拿笔,然后你看到一个糖果棒开始吃它,当你完成后,你忘记了笔。你“递归”了一个级别,从笔问题到直板问题,你的心理堆栈太深了(只有两个级别,但这就足够了)。如果你反而抓住了糖果棒,但是在你打开它并开始吃它之前,还找到了笔(我能想出的最佳迭代方法),你可以做到这两点而不会忘记。解决程序问题的方式应该与解决问题的方式完全相同,因为这是了解代码执行情况的唯一方法。 Python是一种非常好的语言,因为它的高级接口让你可以做到这一点(至少比在低级语言中更常见)。 使用这个事实!
答案 3 :(得分: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 [])
答案 4 :(得分:2)
这是一种简单的pythonic方式:
>>> mylist = range(30)
>>> def func(l):
... return [i-1 for i in l]
>>> func(mylist)
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28]
说明:
我使用list comprehensions为mylist
中的每个元素创建了一个新列表,其中的值比它的值小1。
您的代码没有任何问题,除非您不止一次使用它:
>>> recurseDecrMap(l)
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28]
>>> recurseDecrMap(l)
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28]
要避免这种情况,请查看this answer。
答案 5 :(得分:2)
比较各种方法:
In [1]: import sys
In [2]: sys.setrecursionlimit(10**5)
In [3]: from so import *
In [4]: %timeit recur(range(10**4)).show()
10 loops, best of 3: 18.2 ms per loop
In [5]: %timeit recurse1(range(10**4))
1 loops, best of 3: 559 ms per loop
In [6]: %timeit recurse2(range(10**4))
1 loops, best of 3: 1e+03 ms per loop
In [7]: %timeit recurse3(range(10**4))
1 loops, best of 3: 1.02 s per loop
In [8]: %timeit recurse4(range(10**4))
1 loops, best of 3: 596 ms per loop
<强>代码:强>
class recur:
# No extra memory is required in this method
def __init__(self,lis):
self.lis=lis
self.len=len(self.lis)
self.rec(0)
def show(self):
return self.lis
def rec(self,n):
if n!=self.len:
self.lis[n]-=1
self.rec(n+1)
def recurse1(l,lis=None):
lis=lis if lis is not None else []
if l:
lis.append(l[0]-1)
return recurse1(l[1:],lis)
else:
return lis
def recurse2(l):
return [l[0]-1] + recurse2(l[1:]) if l else []
def recurse3(l):
if len(l) == 0:
return []
else:
return [l[0] -1] + recurse3(l[1:])
def recurse4(l, x = []):
if len(l) == 0:
return []
else:
x.append(l[0] -1)
recurse4(l[1:], x)
return x
答案 6 :(得分:1)
这是一个递归解决方案,可以处理大型列表而不会达到递归深度限制。通过使用除法和征服,与具有朴素递归的O(N)相比,递归深度最差为O(log(N))。然而,任何类型的递归对于这个问题都是一个很差的技术选择,因为它通过一个简单的for循环来解决。
def dec_list(xs, a, b):
if b == a + 1:
xs[a] -= 1
if a + 1 >= b: return
mid = (a + b) // 2
dec_list(xs, a, mid)
dec_list(xs, mid, b)
def dec(xs):
dec_list(xs, 0, len(xs))
xs = range(1001)
dec(xs)
print xs