繁体   English   中英

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

[英]Passing a slice to recursive function in Python

我想我了解递归函数和切片的基本原理(分别),但是我很难将它们组合在一起。 我不明白将切片或列表传递给以下函数时会发生什么。

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

这是包含以下代码的线程: 了解Python中的递归

我想我真的将从逐步了解调用该函数时发生的事情中受益。

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

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

在这里,基本情况是if not ls ,当ls为空列表时将为true。

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

然后,将第一个元素添加到递归调用的结果中并返回。 因为将会有一个递归调用用于元件ls ,在各编号ls得到在转弯是一个弹出并求和,即, 消耗掉

逐步进行操作,我们将添加

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

这是

1 + 3 + listSum([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_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

但是Python实际上并没有消除尾部调用的功能,因此您仍然必须做其他事情以确保堆栈安全。


每天吸烟高阶功能

使用headtail我们摆脱了[0][1:]的繁琐(和丑陋),但是列表遍历的这种模式是如此普遍,以至于我们甚至可以完全不用思考这个级别!

让我们回顾一下我们的函数list_sum 该函数遍历列表并使用内置的+函数执行添加。 如果要用*代替所有元素而不是+怎么办?

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

def list_product (ls):
  if is_empty (ls):
    return 1
  else:              
    return head (ls) * list_product (tail (ls))

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

唯一不同的是将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

并且可以使用其他高阶函数来构建高阶函数。 然后在不知不觉中,您正在进行各种高级转换和遍历!

请注意,此时我们不考虑head还是tail 诸如not []ls[0]ls[1:]之类的难以理解的事情是视线之外的,因此很容易引起注意。

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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM