R:初学者问题:函数上的递归函数

时间:2019-09-27 06:53:56

标签: r

我有一个问题。我在网上阅读解决方案的主要问题是我无法理解其中的95%,因为答案通常过于技术性。

问题:我创建了一个返回一个答案的基本函数。现在,我需要使这个相同的函数重复N / 2次并返回N / 2个答案。

基本功能如下。用户使用变量N输入该函数。假设他输入N = 100,该函数将生成列表a,列表b和列表c。然后,函数对达到标准的次数进行计数并返回计数值。在基本情况下,使用列表a的前10个元素创建列表b,使用其余N-10个元素创建列表c。

f <- function (N) {
  count <- 0
  for (nn in 1:100) {
    a <- sample(1:N)
    b <- a [1:10] 
    c <- a [11:N]
    pass <- which(c>=max(b))
    if (length(pass) == 1) {
        count <- count + 1
    }
  }
  return (count)
}

answer <- f(100)
answer

递归函数必须使此基本函数重复N / 2次。列表b和c的划分不再基于10个元素和(N-10)个元素。现在,它基于1),N-1个元素,然后2)2,N-2个元素,然后3)3,N-3个元素,依此类推,直到N / 2种情况(这两个列表均被均分) )。

因此,我尝试了此操作,但它不起作用。我需要一个可以生成N / 2个答案的递归函数,这对于每种情况都是一个答案。因为我真的是编程新手,所以我希望这些建议能够明确。我可能没有能力理解隐式和部分代码。

感谢大家这么仁慈,并抽出宝贵的时间来帮助他人。

f <- function (N) {
  for (mm in 1: N/2) {
    number <- list()
    count <- 0
    for (nn in 1:100) {
      a <- sample(1:N)
      b <- a [1:mm] 
      c <- a [mm+1:N]
      pass <- which(c>=max(b))
      if (length(pass) >= 1) {
        count <- count + 1
      }
    }
    number[mm] <- count
  }
}

answer <- f(100)
answer
# NULL

有用的评论者(Oliver)提出的最新编辑代码如下。但这仅适用于一种情况。基本上,该函数尝试将100个随机数的列表分为b和c两部分。然后,它尝试查看c是否仅包含一个比b中的最高数字高的数字。 for循环(mm in 1:(N / 2))模拟b和c的连续切片动作。它以1开始,以50(N / 2)结尾。当它为1时,b具有1个元素,而c具有100-1个元素,当它为2时,b具有2个元素,而c具有98个元素……最后一种情况是b和c都具有50个元素。

f <- function (N) {
  for (mm in 1: (N/2)) {
    number <- list()
    count <- 0
    for (nn in 1:100) {
      a <- sample(1:N)
      b <- a [1:mm] 
      c <- a [mm+1:N]
      pass <- which(c>=max(b))
      if (length(pass) == 1) {
        count <- count + 1
      }
    }
    number[mm] <- count
  }
  number
}

bb <- f(100)
bb

[[46]]
NULL

[[47]]
NULL

[[48]]
NULL

[[49]]
NULL

[[50]]
[1] 26

如果代码正常工作,则[46],[47],[48]和[49]的预期答案应为20+,而不是NULL。我相信number[mm] <- count的代码无法正常工作。我相信number[mm]不能成功传输到最终代码number,除了number[50]可以正确传输之外。

2 个答案:

答案 0 :(得分:3)

欢迎来到SO,谢谢您提出的问题。

首先要弄清楚。递归是指在与下面的示例(不是很明确)相同的函数中调用函数:

f <- function(x){
    some code
    n <- f(x2)
    some more code
    return(x3)
}

现在解决您的问题。您已接近所需的答案。在此过程中搞砸了三件事,

  1. 记住您的括号。
  2. 返回输出
  3. 在每次迭代时重置number

对于1。R从左到右读取代码,并且在计算代码方面将非常严格。 1:N/2等效于1: N/2,等效于c(1, 2, ..., N) / 2。您正在寻找1:(N/2)seq(1, N/2),并且您可能想使用floorceiling来舍入N/2的不均匀结果,例如{ {1}},5/2=2.5

对于2.,您当前未从函数中返回任何内容。在13/2=6.5中,您可以使用R显式地返回一个值,或者您可以简单地键入对象/数字作为函数中的最后一项。

对于3,请注意,在外部循环中,您正在调用return(...)。在外循环的每次迭代中,这将重置计数列表,从而删除所有先前的答案。这应该移动

将它们放在一起,使一段正确的代码相当于以下示例:

number <- list()

我不介意给出一些一般性建议,但是对我来说,尚不清楚该功能的整体情况。

答案 1 :(得分:1)

看到您的第一个功能按预期工作,在此基础上创建第二个功能似乎是合理的。如果我们通过将分割点变量设为可分配和可修改的参数来对其进行修改,则可以轻松地创建第二个循环简单地遍历分割点的函数。

f <- function(N, d) {
  count <- 0
  for (nn in 1:100) {
    a <- sample(1:N)
    b <- a[1:d]
    c <- a[(d+1):N]
    pass <- sum(c >= max(b))
    if (pass == 1) {
        count <- count + 1
    }
  }
  count
}

set.seed(1)
f(50, 10)
# [1] 16


f2 <- function(N) {
    l <- floor(N/2)
    v <- vector(length=l)
    for (i in 1:l) {
        v[i] <- f(N, i)
    }
    v
}

set.seed(1)
f2(10)
# [1]  9 13 26 30 27

正如其他人所述,这不是递归函数,而是迭代函数。遍历整数1:floor(1/N)


如果您想了解递归函数,建议您从简单的f.ex开始。斐波那契数列生成器之一。在这里,您可以看到fib()本身在fib()内部被调用,并且每次调用时,x都会扩展为最后两个元素之和,而n会减少与一个。这一直持续到n为零为止,然后返回x

fib <- function(x, n) {
    if (n > 0) {
        x <- c(x, sum(tail(x, 2)))
        fib(x, n-1)
    } else {
        x
    }
}

fib(c(1, 1), 10)
#  [1]   1   1   2   3   5   8  13  21  34  55  89 144