在Python中将切片传递给递归函数

在Python中将切片传递给递归函数,python,list,recursion,slice,tail-recursion,Python,List,Recursion,Slice,Tail Recursion,我想我理解递归函数和切片(单独)的基本原理,但是我很难把它们放在一起。我不明白当您将一个切片或一个列表传递给下面的函数时会发生什么 def listSum(ls): # Base condition if not ls: return 0 # First element + result of calling `listsum` with rest of the elements return ls[0] + listSum(ls[1:]) l

我想我理解递归函数和切片(单独)的基本原理,但是我很难把它们放在一起。我不明白当您将一个切片或一个列表传递给下面的函数时会发生什么

def listSum(ls):
    # Base condition
    if not ls:
        return 0

    # First element + result of calling `listsum` with rest of the elements
    return ls[0] + listSum(ls[1:])

listSum([1, 3, 4, 5, 6])
19
这是包含以下代码的线程:

我想我真的会受益于对调用函数时发生的情况的演练


该线程有许多不同递归函数的示例,具有预期的输出。我对后续示例的理解甚至比我上面复制的示例还要少。

递归的基本概念是,每次调用都会消耗部分输入,并将其减少到与基本情况匹配为止

这里,基本情况是
如果不是ls
,当
ls
是空列表时,这将是真的

消耗是通过切片完成的:每个调用传递一个比上一个短一个元素的列表。这是通过
listSum(ls1:])
实现的,它在由ls的所有元素组成的列表上调用
listSum
,第一个元素除外

然后将第一个元素添加到递归调用的结果中并返回。由于将对
ls
的元素进行一次递归调用,
ls
中的每个数字依次被弹出并求和,即被消耗

一步一步地看,我们要添加

1+列表总和([3,4,5,6])

那是

1+3+列表总和([4,5,6])

那是

1+3+4+listSum([5,6])

那是

1+3+4+5+listSum([6])

那是

1+3+4+5+6+listSum([])

因为基本情况,这是

1+3+4+5+6+0


它是19。

列出遍历婴儿步

对于使用递归遍历列表,只有三件事是重要的

  • 空列表-总是在做任何事情之前检查您的列表是否为空
  • 列表的标题–第一项
  • 列表尾部–除第一项外的整个列表
好的,这是我们用来编写程序的函数

def is_empty (ls):
  return ls == []

def head (ls):
  return ls[0]

def tail (ls):
  return ls[1:]
函数的使用非常简单

is_empty ([])           # => True
is_empty ([ 1, 2, 3 ])  # => False

head ([ 1, 2, 3 ])      # => 1

tail ([ 1, 2, 3 ])      # => [2,3]
好的,让我们来编写我们的
list\u sum
函数——我想你会同意,由于我们定义了列表帮助程序,我们最终得到了一个非常可读的程序

def list_sum (ls):
  if is_empty (ls):
    return 0
  else:
    return head (ls) + list_sum (tail (ls))

print (list_sum ([ 1, 2, 3, 4, 5, 6, 7 ]))
# => 28
但是您用尾部递归标记了它,因此在可选参数和默认值的帮助下,我们可以将递归调用移动到尾部位置。粗体的变化

def list_sum (ls, acc = 0):
  if is_empty (ls):
    return acc
  else:
    return list_sum (tail (ls), head (ls) + acc)

print (list_sum ([ 1, 2, 3, 4, 5, 6, 7 ]))
# => 28
唯一不同的是
0
更改为
1
+
更改为
*
。我们不想每次我们想用一个列表做一些事情时都重写所有这些。如果我们使用函数参数抽象这些值,我们就可以在这个漂亮的小程序中捕捉列表遍历的本质

from operator import add, mul

def list_reduce (f, acc, ls):
  if is_empty (ls):
    return acc
  else:
    return list_reduce (f, f (acc, head (ls)), tail (ls))

def list_sum (ls):
  return list_reduce (add, 0, ls)

def list_product (ls):
  return list_reduce (mul, 1, ls)

print (list_sum ([ 1, 2, 3, 4, 5, 6, 7 ]))
# => 28

print (list_product ([ 1, 2, 3, 4, 5, 6, 7 ]))
# => 5040
高阶函数可以使用其他高阶函数构建。然后在你知道之前,你正在做各种各样的高级转换和遍历

请注意,在这一点上,我们并没有考虑头或尾。像
not[]
ls[0]
ls[1:][/code>这样的东西是看不见的,因此也就忘了

def map (f, ls):
  return list_reduce (lambda acc, x: acc + [ f (x) ], [], ls)

def square (x):
  return x * x

print (map (square, [ 1, 2, 3, 4, 5, 6, 7 ]))
# => [1, 4, 9, 16, 25, 36, 49]

切片只是创建一个新列表。你并不是真的传递一个片段,而是从一个列表中获取一个片段来创建一个新的列表,然后传递它如果你需要一个遍历的话,试着运行你的代码,点击“可视化执行”,它会加上1加上列表的其余部分,而不加1,所以
1+(2+(3+(4+(5+(6+0)())”)
列表的总和是列表中的第一件事(
ls[0]
)加上其余部分的总和(
listSum(ls[1://code>)。splice返回一个新列表。函数listSum获取一个列表。这是一个匹配项!递归很简单“sum=first+sum(rest)”。
def map (f, ls):
  return list_reduce (lambda acc, x: acc + [ f (x) ], [], ls)

def square (x):
  return x * x

print (map (square, [ 1, 2, 3, 4, 5, 6, 7 ]))
# => [1, 4, 9, 16, 25, 36, 49]