首页 > 解决方案 > 递归替换函数需要说明

问题描述

嗨,我对 javascript 编程很陌生。我正在学习 FCC 和 Grasshopper。在 Grasshopper 上,我被困在关于递归替换功能的课程上。我不明白。如果有人解释,这将是一个很大的帮助。所以根据教训,它是这样的:

var wrongDocument = "This document  ahs a typo in it. The other one ahs typo too.";
function changeSpelling(string, oldPart, newPart) {
  if (string.includes(oldPart) === false) {
    return string;
  }
  string = string.replace(oldPart, newPart);
  return changeSpelling(string, oldPart, newPart);
};
console.log(wrongDocument);
console.log(changeSpelling(wrongDocument, 'ahs', 'has'));

我面临的问题是我不明白 return 语句为什么以及如何调用它所在的函数?

其次,为什么这不能用 if...else 语句来解释?第三,我在理解参数和参数时遇到问题。所以我写了以下代码。这绝对不会取代所有的拼写,但我无法进一步理解。

var chat = "This document ahs a typo in it. The other one ahs too.";
var fix = (a, b) => {
    if (chat.includes(a) === false) {
        return chat;
    }
    else {
        return chat.replace(a, b)
    }
}

console.log(chat);
console.log(fix('ahs', 'has'));

请解释递归函数的工作原理以及我的代码有什么问题。

标签: javascriptfunctionrecursion

解决方案


我面临的问题是我不明白 return 语句为什么以及如何调用它所在的函数?

你是对的。这将是一个大问题,递归将永远追逐它的尾巴,除了这一点:

  if (string.includes(oldPart) === false) {
    return string;
  }

所以递归调用 ( return changeSpelling(string, oldPart, newPart)) 不是从函数返回的唯一方法。还有至少一个(在这种情况下只有一个)基本情况在没有递归调用的情况下返回。此外,每次递归调用都会朝着基本情况前进,因为每次出现特定错字的实例都会减少一次。如果这两个是真的,那么递归调用是定义良好的。

您的替代解决方案仅替换错字的第一个实例。这就是它的设计目的。有几种方法可以解决这个问题。也许最明显的一个是将您的代码包装在一个while循环中,如下所示:

const fix = (chat, a, b) => {
  if (chat .includes (a) === false) {
    return chat;
  }
  else {
    return chat.replace(a, b)
  }
}

const fixAll = (chat, a, b) => {
  let test = chat
  while (test .includes (a)) {
    test = fix (test, a, b)
  }
  return test
}

const chat = "This document ahs a typo in it. The other one ahs too.";

console .log (chat)
console .log (fixAll (chat, 'ahs', 'has'))

(请注意,我现在将字符串传递给函数。这使得代码更易于理解和测试,只使用它的参数,除了返回一个值之外什么都不做。这就是纯函数的定义。你会发现纯函数有很多优点。)

但其中有一些真正的冗余。我们没有充分的理由检查两次是否包含该字符串。fix这可以通过将相关工作从into内联来清理fixAll

const fixAll = (chat, a, b) => {
  let test = chat
  while (test .includes (a)) {
    test = test .replace (a, b)
  }
  return test
}

const chat = "This document ahs a typo in it. The other one ahs too.";

console .log (chat)
console .log (fixAll (chat, 'ahs', 'has'))

这是解决此问题的完全合理的方法。大概您的课程是关于教您一种替代技术,即使用递归来解决问题。所以让我们重新开始。

问:我们想做什么?

A:用正确的字符串替换所有出现的错字。

问:我们应该怎么做?

答:你什么意思?

问:嗯,我们首先应该做什么?

A:我猜是替换第一个。

问:我们如何做到这一点?

A:string .replace (oldPart, newPart)

问:接下来是什么?

A:嗯,那我们换第二个。

问:如何?

答:同理,string .replace (oldPart, newPart)

问:然后呢?

- 答:第三个,同样的方式。

问:然后呢?

答:嗯,我们一直这样做,直到不再有拼写错误。

问:我们怎么知道没有?

答:我们与string .includes (oldPart)

问:我们什么时候做这个测试?

- 答:更换前。

问:每次?

答:是的。

问:好的,那么。你能把它写成一组明确的说明吗?

答:来了

1. Check if the string has any misspellings
2. If not, return it as is
3. If so, replace it with the good string
4. Go back to step 1.

问:看起来不错。但是当您返回到第 1 步时,您使用什么字符串进行测试?

A:我们刚刚用正确的单词替换了拼写错误的单词。

问:那么我们如何将它写成一个函数呢?

答:这个怎么样?

const changeSpelling = (string, oldPart, newPart) => {
  if (!string .includes (oldPart)) {
    return string
  }
  string.replace (oldPart, newPart)
  // hmm, do it again here.  But how?
}

问:是的。现在你想再做一次。您已经有一个功能可以做到这一点;这就是你在写的。我们不能叫它吗?

A:但它不完整。

问:这一步就完成了。在这里再次调用该函数会是什么样子?

答:我想是这样的:

const changeSpelling = (string, oldPart, newPart) => {
  if (!string .includes (oldPart)) {
    return string
  }
  string .replace (oldPart, newPart)
  changeSpelling (string, oldPart, newPart)
}

问:越来越近了,但最后我们会返回什么?

A:哦,对了,应该是return changeSpelling (string, oldPart, newPart)

问:正确,但是我们应该将什么字符串传递给它?

A:我们刚换的那个。

问:是的,但.replace不会更改您的字符串,它会创建一个包含替换的新字符串。

A:哦,所以我们需要保存更改后的字符串。这个怎么样?

const changeSpelling = (string, oldPart, newPart) => {
  if (string .includes (oldPart) === false) {
    return string
  }
  const newString = string .replace (oldPart, newPart)
  return changeSpelling (newString, oldPart, newPart)
}

问:看起来不错。它是否遵循我们提到的递归规则?

A:嗯,它至少有一个基本案例。另一个规则是什么?

问:递归案例必须朝着您的基本案例之一取得进展。

A:是的,由于我们已经替换了其中一个错别字,我们正朝着没有任何错别字的情况前进。所以是的。

问:我认为它会起作用。你满意吗?

答:我认为是的。你会这样做吗?

问:嗯,我非常喜欢使用表达式而不是控制语句,并且不分配不必要的临时变量,所以我的看起来有点不同。但基本的想法是一样的。

A:你能告诉我你会怎么做吗?

问:当然,我的看起来更像这样:

const changeSpelling = (oldPart, newPart) => (string) =>
  string .includes (oldPart)
    ? changeSpelling (oldPart, newPart) (string .replace (oldPart, newPart))
    : string

A:看起来很不一样。为什么说是一样的?

问:我认为这是另一天的教训。


推荐阅读