【问题标题】:Why does this function work with min, but not without?为什么这个函数可以和 min 一起工作,但不能没有?
【发布时间】:2017-04-04 03:26:57
【问题描述】:
def edDistRecursive(a,b):
    #print(a, 'a')
    #print(b,'b')

    if len(a) == 0:
        return len(b)

    if len(b)==0:
        return len(a)



    delta = 1 if a[-1] != b[-1] else 0
    return min(edDistRecursive(a[:-1], b[:-1]) + delta,   edDistRecursive(a[:-1], b)+1,  edDistRecursive(a, b[:-1]) +1)

edDistRecursive('actor','racto')

2

但是,如果我在没有min 的情况下运行它,

TypeError: can only concatenate tuple (not "int") to tuple

这是一种用于遗传学(近似匹配)的算法,用于确定需要多少次编辑才能匹配ab。我想如果我在没有 min 的情况下运行它,我将能够看到每个函数产生了多少编辑。

编辑:我想我理解输出是一个元组,但我也有点困惑。
如果我删除其他两个函数,则像这样简化函数

def edDistRecursive(a,b):
    #print(a, 'a')
    #print(b,'b')

    if len(a) == 0:
        return len(b)

    if len(b)==0:
        return len(a)



    delta = 1 if a[-1] != b[-1] else 0
    return edDistRecursive(a[:-1], b[:-1]) + delta 


edDistRecursive('actor','racto')  returns a value of  5.

为什么这里可以毫无问题地添加delta?

下面是另一个例子

def sum(x,y):
    x =3
    y =2

    return x+y, y


(sum(2,3))

即使是这样的输出是一个元组的东西,对其元素之一的加法运算也没有问题。

在我上面的函数中,值 delta 或 +1 被添加到元组中,这就是引发错误的原因,但似乎 int 值没有被添加到整个元组中。事实上,元组由 (function + int) 组成。所以当元组本身的一个元素是(函数+ int)时,我看不到我是如何添加到元组中的。

x,y,z = edDistRecursive('actor','racto') 似乎也导致了同样的错误。

我以为通过给每个函数((edDistRecursive(a[:-1], b[:-1]) + delta), (edDistRecursive(a[:-1], b)+1), (edDistRecursive(a, b[:-1]) +1))加括号,

Python 可以将元组的每个元素视为function + int,但我遇到了同样的错误。

有没有办法获取每个函数的值,这是我最初的目标?

【问题讨论】:

  • min 是一个函数,括号中的逗号分隔列表是该函数的参数。它将返回其中一个整数。如果没有min,括号中的逗号分隔列表是一个元组,你不能在一个元组中添加一个to。

标签: python recursion min


【解决方案1】:

如果您考虑在递归的倒数第二级(参见下面的编辑)发生的情况,对edDistRecursive(a[:-1], b[:-1]) 的递归调用将返回一个整数元组。当程序尝试将 delta 值(它是一个 int)连接到此元组时,将引发错误。通过使用 min,您可以保证返回类型始终相同并且与您的实现兼容。

编辑:让我们逐步通过一个示例,以便我们可以更直接地查看正在发生的事情。对于这个例子,让我们使用 min 以便我们可以看到问题出在哪里。

为使示例简单,假设我们从

edDistRecursive(['x','k','z'], ['y','e','d'])

在进行递归调用的某个时刻(即在每个 return 语句中进行第一次递归调用之后),我们将到达

edDistRecursive(['x'], ['y'])

这就是我所说的“递归的最低级别”的意思,但它实际上是“倒数第二级”,因为我们即将达到基本情况。

所以 a = ['x'] 和 b = ['y']。我们现在进入函数并检查前两个 if:
* len(a) == 0 吗?没有。
* len(b) == 0 吗?没有。
* 计算 delta = 1
* return edDistRecursive(a[:-1], b[:-1]) + delta,
edDistRecursive(a[:-1], b) + 1,
edDistRecursive(a, b[:-1]) + 1

现在 Python 将评估第一个递归调用,因为它必须这样做才能真正返回一些东西。

第一个递归调用将是edDistRecursive([], [])。现在让我们看看会发生什么:
* len(a) == 0 吗?是的,已达到基本情况 - 返回 len(b) = 0

所以现在我们回到上一级,回到之前的 return 语句:
return 0 + 1, edDistRecursive(a[:-1], b) + 1, edDistRecursive(a, b[:-1]) + 1

edDistRecursive(a[:-1], b) 将评估为 edDistRecursive([], ['y'])
让我们现在检查一下:
* len(a) == 0 吗?是的,已达到基本情况 - 返回 len(b) = 1

再次返回return语句:
return 0 + 1, 1 + 1, edDistRecursive(a, b[:-1])

edDistRecursive(a, b[:-1]) 将评估为edDistRecursive(['x'], [])。 这是在此级别进行评估的最后一次调用:
* len(a) == 0 吗?没有。
* len(b) == 0 吗?是 - 返回 len(a) = 1

再看一下return语句,现在可以实际返回了:
return 1, 2, 1 + 1

好的,所以递归调用的结果是元组(1, 2, 2)
当它返回到调用它的edDistRecursive(比如edDistRecursive(['x','k'], ['y','e']))时,就会引发异常:

return (1, 2, 2) + delta, edDistRecursive(a[:-1], b) + 1, ...
       |---------------|
       this will raise the exception

我强烈建议您绘制一个与此类似的示例并检查所有递归步骤。尝试不使用 min,然后尝试使用 min - 您应该会注意到在某些级别返回的内容有所不同。

【讨论】:

  • edDistRecursive(a[:-1], b[:-1]) 自己工作正常。
  • edDistRecursive(a[:-1], b[:-1])+ delta 本身似乎工作正常。
  • 而且它没有返回一个整数元组。它返回一个值。
  • 但是如果您删除对 min 的调用,那么第一次(将在达到两个基本情况之一之后发生)您从递归调用中返回结果,它将返回一个三元组价值观。这是您遇到错误的时候。通过调用 min,该方法确实会返回一个值 - 否则将作为元组返回的三个值中的最小值。
  • 你把我弄糊涂了。 edDistRecursive(a[:-1], b[:-1]) 是唯一的一个输出。并且只返回一个值。除非你在谈论所有三个递归输出。
【解决方案2】:

目前尚不清楚“如果我在没有 min 的情况下运行它”的确切含义,但这是显而易见的:表单声明

return min(x, y, z)

返回 xyz 中最小的一个,但声明形式为

return x, y, z

返回包含三个元素 (x, y, z) 的元组。

就这么简单吗?

思考

英语在这里不起作用 ;-) 看一个更简单的例子,它有完全相同的问题:

def f(n):
    if n < 5:
        return n + 1
    return min(f(n // 2) + 1, f(n // 3) + 7)

然后,例如,

>>> f(100)
9

现在带走min

def f(n):
    if n < 5:
        return n + 1
    return (f(n // 2) + 1, f(n // 3) + 7)

然后:

>>> f(100)
Traceback (most recent call last):
  ...
TypeError: can only concatenate tuple (not "int") to tuple

只能建议你一行一行地工作,直到灯亮起。你原来的问题应该会变得一清二楚。

【讨论】:

  • 具有多个值的函数是否总是以元组形式返回?通常,我可以将三个值分配给三个变量,但这也会导致错误。谢谢。
  • 不知道“具有多个值的函数”是什么意思。 return xreturn (x) 返回 x 是什么。 return x,return (x,) 返回一个包含单个元素 x 的元组。 return x, yreturn (x, y) 返回一个包含两个元素的元组。等等。构造元组的是逗号,而不是括号。看起来你的心智模型比事实更复杂 - 所以简化它;-)
  • 嗨蒂姆。谢谢你的回复。即使我的输出是一个元组,我的 ` + delta ` 操作也被应用于元组的一个元素。为什么这个工作但不是我上面的功能? def sum(x,y): x =3 y =2 return x+1, y
  • 对不起,但此时我不知道你在问什么。 return x+1, y 返回 2 元组 (x+1, y),即简单的 (4, 2) 给定 x=3y=2。如果你继续,例如,做42 + sum(3, 2),那么你会得到一个错误,因为int 42不能被添加到元组(4, 2)中。
  • 42 + sum(3, 2) 导致错误,因为输出是 (4,2) 对吗? edDistRecursive(a[:-1], b[:-1]) + delta 不会导致错误(当我删除其他 2 个递归函数时)?我得到的结果是 5。输出似乎总是 Noneint. 现在当我返回所有三个函数时,我假设你在说,那是输出是一个元组的时候?@987654354 @ 如果是这样,那么我的操作没有对整个元组进行。
【解决方案3】:

问题出现在以下部分:

edDistRecursive(a[:-1], b[:-1]) + delta

请记住,delta 是一个数字。您只能将一个数字添加到一个数字。但是,如果之前对edDistRecursive(a[:-1], b[:-1]) 的调用返回一个元组(比如说(1,2,3)),那么您正在尝试进行计算:

(1,2,3) + delta

这是一个错误。

【讨论】:

  • edDistRecursive(a[:-1], b[:-1]) 本身仅在递归结束时返回一个整数。但是,如果添加了 delta,它会返回值 5(因此递归必须发生 5 次)如何将 delta 添加到没有值的递归函数中?
  • 递归函数总是返回一个值。 len(a)len(b)edDistRecursive(a[:-1], b[:-1]) + delta,每一个都恰好是一个数字。
猜你喜欢
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-13
  • 2019-12-28
  • 1970-01-01
  • 2016-05-18
相关资源
最近更新 更多