递归函数返回一个列表

huangapple go评论84阅读模式
英文:

Recursive function that return a list

问题

def sum(x):
    if x == 1:
        return 1
    else:
        return sum(x-1) + x

def factorials(x):
    list1 = []
    for c in range(1, x+1):
        list1.append(sum(c))
    return list1

print(factorials(10))

在第一个函数中,你将 n 作为参数传递,并返回 1 + 2 + 3 + ... + n 的和。

在第二个函数中,你将返回一个包含 n 个和的列表,例如当你调用 factorials(10) 时,输出将会是 [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

我的真正问题是我想知道是否有一种递归的方式来完成第二个函数。我在递归函数中使用列表添加时遇到了困难。

英文:

I want to know how to do the second function recursively.

def sum(x):
    if x == 1:
        return 1
    else:
        return sum(x-1) + x
    
def factorials(x):
    list1 = []
    for c in range(1, x+1):
        list1.append(sum(c))
    return list1

print(factorials(10))

in the first function, you pass n as an argument and return the sum of 1 + 2 + 3 + ... + n

in the second function you will return a list of n sums, for example when you invoke factorial(10), the output is gonna be [1, 3, 6, 10, 15, 21, 28, 36, 45, 55].

My real problem is that I wanna know if have some way to do the second function in a recursive way. I am struggling with list appends in recursive functions.

答案1

得分: 1

几个答案已经向您展示了如何通过调用自身和(同样具有误导性名称的)sum函数使您的factorial函数产生一个列表。但是还没有人注意到,正如此算法将做的那样,重复调用sum是极其浪费的。您需要在factorial递归的每个级别上不断递归sum调用链。

相反,您应该重写您的factorial函数,直接基于列表中的先前值来计算最新的值(递归找到)!以下是示例:

def factorial(n):
    """返回前n个三角数的列表"""
    if n <= 0:        # 这个基本情况只是为了一般安全性
        return []
    if n == 1:        # 这是主要的基本情况,递归在这里结束
        return [1]

    lst = factorial(n-1)  # 递归,返回一个带有n-1个值的列表
    nth_value = lst[-1] * n  # 根据(n-1)th值计算nth值
    lst.append(nth_value)  # 将值添加到列表的末尾
    return lst

如果您实际上想要前n个阶乘,而不是前n个三角数,请将lst[-1]+n替换为lst[-1]*n

英文:

Several answers have shown you how you can have your (misleadingly named) factorial function produce a list by calling itself and the (also misleadingly named) sum function. But nobody has yet noted that calling sum repeatedly, as this algorithm will do, is extremely wasteful. You keep needing to recurse up a chain of sum calls at every level of the factorial recursion.

Instead, you should rewrite your factorial to directly compute the newest values based on the previous values in the list (found recursively)! Here's what that looks like:

def factorial(n):
    &quot;&quot;&quot;Returns a list of the first n triangular numbers&quot;&quot;&quot;
    if n &lt;= 0:        # this base case is just for general safety
        return []
    if n == 1:        # this is the main base case, where our recursion ends
        return [1]

    lst = factorial(n-1)  # recurse, get a list back with n-1 values
    nth_value = lst[-1]+n # compute the nth value based on the (n-1)th value
    lst.append(nth_value) # add the value to the end of the list
    return lst

Replace lst[-1]+n with lst[-1]*n if you actually want the first n factorials, rather than the first n triangular numbers.

答案2

得分: 0

如评论中@SimonUnderwood所指出,这是计算三角数,而不是阶乘。说到这一点,这里有一些代码:

    def triangulars(x):
        if x < 1:
            return []
        return triangulars(x - 1) + [sum(x)]

技巧是在每个递归调用中向列表追加一项。在这种情况下,我通过使用sum计算当前数字的新列表并使用列表的加法运算符将其与其下方的数字的列表合并。

英文:

As pointed out by @SimonUnderwood in the comments, this is computing triangular numbers, not factorial. That being said, here's some code:

def triangulars(x):
    if x &lt; 1:
        return []
    return triangulars(x - 1) + [sum(x)]

The trick is to append an item to the list in each recursive call. In this case, I'm doing it by creating a new list with sum for the current number and using the addition operator on lists to combine it with the list for the number below it.

答案3

得分: 0

首先观察一下:不要将函数命名为 sum,因为在Python中这是一个内置函数。

解决方案在于在递归函数之外声明一个列表,并且您不需要一个 sum 或等效的函数:

def factorials(limit):
    def fact(limit, count: int, alist: list):
        if count > limit:
            return
        alist.append(1 if len(alist) == 0 else alist[-1] + count)
        fact(limit, count + 1, alist)

    list1 = []
    fact(limit, 1, list1)
    return list1

print(factorials(10))

这将产生 [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]。还请注意,这也是一个更符合Python风格的解决方案。

英文:

First an observation: do not name a function sum since that is a built-in function in python.

The solution lies in declaring a list OUTSIDE of the recursive function, and you don't need a sum or equivalent function:

def factorials(limit):
	def fact(limit, count: int, alist: list):
		if count &gt; limit:
			return
		alist.append(1 if len(alist) == 0 else alist[-1] + count)
		fact(limit, count + 1, alist)

	list1 = []
	fact(limit, 1, list1)
	return list1

print(factorials(10))

That produces [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]. Also note that this is also a more python-ish solution.

答案4

得分: 0

你可以使用scan来实现triangle -

from operator import add

def triangle(x):
  return scan(add, 0, range(1, x + 1))

def scan(f, init, ls):
  if not ls:
    return [init]
  else:
    return [init] + scan(f, f(init, ls[0]), ls[1:])
print(triangle(10))
# [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

print(triangle(0))
# [0]
英文:

You could implement triangle using scan -

from operator import add

def triangle(x):
  return scan(add, 0, range(1, x + 1))

def scan(f, init, ls):
  if not ls:
    return [init]
  else:
    return [init] + scan(f, f(init, ls[0]), ls[1:])
print(triangle(10))
# [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

print(triangle(0))
# [0]

答案5

得分: 0

由于您正在进行累积求和(而不是实际的阶乘),您可以使用n(n+1)/2公式(或您自己的sum()函数)来计算每一项:

def factorials(n): 
    return factorials(n-1) + [n*(n+1)//2] if n else []

或者

def factorials(n): 
    return factorials(n-1) + [sum(n)] if n else []

另一种方法是在递归中传递一个部分结果,并在n达到零时将最终列表级联回返回堆栈。每个递归调用只需要使用上一个值和当前长度来计算要添加的下一个条目:

def factorials(n,r=[0]): 
    return factorials(n-1,r+[r[-1]+len(r)]) if n else r[1:]

另一种方法是传递一个计数器,它在n增加时增加,以及一个上次结果值,并将递归列表与新条目级联(可以使用计数器向前计算):

def factorials(n,i=1,r=0): 
    return [] if i>n else [r+i]+factorials(n,i+1,r+i)
英文:

Since you're doing cumulative sums (not actual factorials), you could use the n(n+1)/2 formula (or your own sum() function) to compute each term:

def factorials(n): 
    return factorials(n-1) + [n*(n+1)//2] if n else []

or

def factorials(n): 
    return factorials(n-1) + [sum(n)] if n else []

Alternatively, you can pass down a partial result to the recursion and cascade the final list back up the return stack when n reaches zero. Each recursive call only needs to use the last value and current length to compute the next entry to add:

def factorials(n,r=[0]): 
    return factorials(n-1,r+[r[-1]+len(r)]) if n else r[1:]

Another way is to pass down a counter that increases up to n along with a last result value and concatenate the recursed list with the new entry (which can be computed forward using the counter):

def factorials(n,i=1,r=0): 
    return [] if i&gt;n else [r+i]+factorials(n,i+1,r+i)

答案6

得分: -1

我修正了一些变量命名以澄清,还改变了一些条件,以便在 x &lt;= 0 时不会无限循环。

def triangle(x):
    if x &lt;= 1:
        return x
    else:
        return triangle(x-1) + x

# 虽然这不会影响这个特定的示例,但通常不建议将列表用作默认值。
def get_triangular_sequence(x, found = None):
    if found is None:
        found = []
    if x &lt;= 1:
        found.append(x)
        return found
    found.append(triangle(x))
    return get_triangular_sequence(x-1, found)

print(get_triangular_sequence(10))

列表将按从大到小的顺序排列,但如果您希望,可以轻松地反转它。

英文:

I fixed some variable naming to clarify and changed some conditions so that it would not infinitely loop if x &lt;= 0

def triangle(x):
    if x &lt;= 1:
        return x
    else:
        return triangle(x-1) + x
    

# Although it doesn&#39;t impact this particular example, it&#39;s generally not recommended to use lists as default values. 
def get_triangular_sequence(x, found = None):
    if found is None:
        found = []
    if x &lt;= 1:
        found.append(x)
        return found
    found.append(triangle(x))
    return get_triangular_sequence(x-1, found)


print(get_triangular_sequence(10))

The list will be in greatest to least order, but it can be easily flipped if you so desire.

答案7

得分: -3

递归函数在Python中性能严重不足,应尽量避免使用递归解决方案,因为迭代实现几乎总是更快且更便宜。

递归函数会调用自身,返回递归情况或基本情况。基本情况最终会上升并结束递归,产生最终值。

例如,考虑这个递归定义的阶乘函数:

def factorial(n: int) -> int:
    if n == 0:
        return 1  # 这只有在第一轮递归中才可能到达,更像是提前结束而不是基本情况
    elif n == 1:
        # 基本情况
        return n
    elif n < 0:
        raise ValueError("负数没有阶乘")
    else:
        # 递归情况
        return n * factorial(n-1)

处理一些边缘情况后(n=0, n<0),剩下两种情况:

  • 基本情况:如果 n == 1,则停止递归并返回 1
  • 递归情况:如果 n >= 2,则将 n 乘以 factorial(n-1) 的下一个结果

如果你想要一个能够递归计算一系列这些值的函数,你可以这样做...

# from typing import List
def factorial_range(start: int, stop: int, _cur=None) -> List[int]:
    if start >= stop:
        raise ValueError('范围无效')
    if _cur is None:
        _cur = start
    if _cur == stop:
        # 基本情况
        return []
    else:
        # 递归情况
        return [factorial(_cur)] + factorial_range(start, stop, _cur+1)
英文:

I would be remiss if I did not mention at the top that recursive functions are SERIOUSLY UNDERPERFORMANT in Python. You should avoid recursive solutions whenever possible when writing Python, as the iterative implementation is almost always faster and cheaper.


Recursive functions call themselves, returning either the recursive case or the base case. The base case will eventually bubble up and end recursion, producing your final value.

Consider, for instance, this recursively-defined factorial function:

def factorial(n: int) -&gt; int:
    if n == 0:
        return 1  # this should only be possible to reach
                  # on the first round of recursion, and
                  # is more of an early-out than a base case
    elif n == 1:
        # base case
        return n
    elif n &lt; 0:
        raise ValueError(&quot;Factorial for negative number&quot;)
    else:
        # recursive case
        return n * factorial(n-1)

After dealing with some edge cases (n=0, n<0), you have two cases left:

  • Base case: if n == 1, stop recursing and return 1
  • Recursive case: if n >= 2, multiple n by the next result of factorial(n-1)

If you wanted a function that recursively calculated each of a number of these, you could do...

# from typing import List
def factorial_range(start: int, stop: int, _cur=None) -&gt; List[int]:
    if start &gt;= stop:
        raise ValueError(&#39;Invalid range&#39;)
    if _cur is None:
        _cur = start
    if _cur == stop:
        # base case
        return []
    else:
        # recursive case
        return [factorial(_cur)] + factorial_range(start, stop, _cur+1)

huangapple
  • 本文由 发表于 2023年5月26日 11:29:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76337481.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定