这个功能对我来说没有意义。我已经在所有地方添加了印刷语句,以弄清楚发生了什么,我仍然没有得到它。如果有人能向我解释这一点,我将不胜感激。
def f(s):
if len(s) <= 1:
return s
return f(f(s[1:])) + s[0]
print(f("mat"))
这就是我看到的情况。所以我们从长度为3的字符串开始并绕过if语句。我们首先在内部f(s [1:])上工作。所以现在我们有一个长度为2的字符串(&#34; at&#34;)再次绕过if语句并输入f(s [1]),它给出了长度为1的字符串(&#34; t&#34) ;)最后输入if语句并返回&#34; t&#34;。这就是我的道路变冷的地方。
从我的print语句中,我看到一个长度为2的新字符串被创建,随后的#34; a&#34;得到回报。最终产品最终成为&#34; atm&#34;。我得到了&#34; m&#34;由于&#34; + s [0]&#34;被标记在最后部分但为什么它&#34; atm&#34;而不是&#34; tam&#34;?
我老老实实地花了几个小时在这上面,不能下雨。任何帮助将不胜感激。
答案 0 :(得分:5)
通过使用他们正在做的事情填写函数调用,将整个事情扩展为很长的步骤。处理最深/最嵌入的第一个括号。在添加之前处理函数调用。
为了清楚起见,我将忽略所有字符串引号。
f(mat) -> mat is 3 chars:
call f on at for f(at), and call f on that.
add m.
f(f(at))+m -> inner f(at), at is 2 chars:
call f on t for f(t), and call f on that.
add a.
f(f(f(t))+a)+m -> innermost f(t) returns t.
f(f(t)+a)+m -> inner f(t) returns t as well.
f(ta)+m -> [here, the first f(f(at)) has been reduced to f(ta)]
ta is 2 chars:
call f on a for f(a), and call f on that.
add t.
f(f(a))+t+m -> inner f(a) returns a.
f(a)+t+m -> f(a) returns a as well.
a + t + m ->
atm -> everything reduces to atm.
答案 1 :(得分:1)
简短版本:a
和t
交换两次,因此内部f("at")
调用返回"ta"
,然后是外{ {1}}调用已通过f()
并返回"ta"
。
更长的版本:我不会明确地为你拼出它,因为你不会那么学习,但考虑这个函数,完全等同于:
"at"
当您致电def f2(s):
if len(s) <= 1:
return s
x = f2(s[1:])
return f2(x) + s[0]
print(f2("mat"))
时,f2("mat")
为s[1:]
。现在,"at"
会返回什么?将该值(f2("at")
的值)插入x
表达式,看看你得到了什么。
尝试浏览f2(x) + s[0]
和f2("at")
的值,看看您是否能够发现正在发生的事情。如果您在另外15-20分钟的工作后仍然需要帮助,请对此答案发表评论,然后再对其进行扩展。
答案 2 :(得分:1)
这实际上是一个令人惊讶的有趣功能,我可以看出为什么它让你感到困惑。我假设你试图将这个功能理解为一个整体,而这实际上并不适用于此。
现在,这个函数有两个部分 - 处理它是空的情况或字符串中只有一个字母,并处理字符串中至少有两个字母的情况。但是,这是欺骗性的,因为它有效地应用了不同的操作,具体取决于字符串中有多少个字母!
因此,让我们以非递归的方式考虑函数:如果字符串太短,只需返回字符串。否则,将某些函数两次应用于除字符串的第一个字符之外的所有字符,然后将第一个字符添加到结果的末尾。不要认为它是同一个功能,只要把它想象成一些未知的功能。
在代码中:
def f(s):
if len(s) <= 1:
return s
return other_f(other_f(s[1:])) + s[0]
打下兔子洞:
那么我们如何定义这个other_f
?让我们看看它对于某些字符串长度需要具有什么样的行为。如果len(s)
为2,那么我们知道s[1:]
是一个字符,因此other_f
只会返回s[1:]
。在代码中:
def f2(s): # For when len(s)==2
#if statement is not used
#return other_f(other_f(s[1:])) + s[0] becomes
#return other_f(other_f(s[1])) + s[0] becomes
#return other_f(s[1]) + s[0] becomes
return s[1] + s[0]
它只是交换两个字母。让我们使用字符串'abc'
来查看下一个字符串的内容:
def f3(s): # For when len(s)==3
#if statement is not used
#return other_f(other_f(s[1:])) + s[0] becomes
#return f2(f2('bc')) + 'a' becomes
#return f2('cb') + 'a' becomes
#return 'bc' + 'a'
return s[1:] + s[0]
因为应用于'bc'的函数交换它们并且被应用两次,所以该函数会自行撤消。所以在这种情况下,我们只需将第一个字母放在字符串的末尾。
def f4(s): # For when len(s)==4
#return f3(f3(s[1:])) + s[0] becomes
#return f3(f3('bcd')) + 'a' becomes
#return f3('cdb') + 'a' becomes
#return f3('dbc') + 'a' becomes
#'dbca'
return s[3] + s[1:3] + s[0] # swap first and last letter
def f5(s): # For when len(s)==5
#return f4(f4(s[1:])) + s[0]
#return f4(f4('bcde')) + 'a'
#swapping first and last letter twice just swaps then swaps back
#return 'bcde' + 'a'
return s[1:] + s[0]
所以看起来我们在这里有一个很好的模式 - 如果字符串有偶数个字母,则交换第一个和最后一个字母。如果它有一个奇数字母,请将第一个字母移到最后!
......不。该模式以f5
结尾。如果你使用像'abcd ...'这样的字符串运行函数,你可以很容易地看到每个级别如何移动字母。
f | output
----------
f6|'defbca'
f7|'cdbfgea'
f8|'cgefbhda'
f9|'fecihbgda'
正如你所看到的,对于更长的字符串,除了第一个字符总是在字符串的末尾结束之外,字母被很好地加扰。想到它的最好方法是(用一行代码)你已经设法为每个字符串长度写一个不同的函数(有些函数的行为方式相同,如f3
和{{1 }})。每个函数都依赖于它上面的函数,所以因为f5
下来很好地随机化了字符串,每个进一步的函数也应该很好地随机化字符串。