0

I'm trying to create a function that takes two arguments. It will repeatedly call the first argument, in my case

f()

until f returns that same value 3x in a row. It will then call the second argument

g()

and if g returns the same value as f returned earlier, then the function must return this value. Otherwise it will go back and call the first argument f() again and repeat the cycle.

This is what I have so far.

call_until = function(f, g) {
    while(1) {
        n = f %>% chunk(3) %>% filter(f, function(v) length(unique(v)) == 1)
        x = n()[1]
        if (x == g()) {
            return(x)
        }
    }
}

For example, if f returns 4 three times in a row, then go to g. If g equals what f returned three times in a row (which in this example is 4); so if g == 4, then call_until should return 4.

skatofia
  • 17
  • 4
  • 1
    Ending with `any thoughts?` will likely not get you the feedback you're looking for. It's unclear if you're having an issue - does your function work or not work? - and what that issue is. You'll also get more help if you provide a reproducible example - input -> expected-output. – CPak Mar 28 '18 at 16:25
  • Case matters, you have an `X` and an `x` which will cause problems. And I echo everything CPak says. Can't tell much without an example and a clearer question than "Any thoughts". – Gregor Thomas Mar 28 '18 at 16:27
  • @Gregor changed it – skatofia Mar 28 '18 at 18:05

3 Answers3

0

Here is an example of how that could be implemented:

f <- function(){
  return(sample(1:10,1))
}
g <- f

call_until <- function(f, g){
  results <- c(f(), f(), f())
  test <- g()
  while(length(unique(results)) > 1 || test != results[3]){
    results <- c(results[2:3], f())
    test <- g()
  }
  return(test)
}

Now here I created some simple functions f;g which will randomly pick between 1-10 (without even requiring arguments as input). So that may need to be adapted. Here are some outputs:

> call_until(f,g)
[1] 3
> call_until(f,g)
[1] 7
> call_until(f,g)
[1] 10
> call_until(f,g)
[1] 9
niko
  • 5,253
  • 1
  • 12
  • 32
0

Recursive function is probably not a best choice, consider this answer as an option.

f <- function(){
    sample(1:2, 1)
}

g <- function(){
    sample(1:2, 1)
}

fg <- function(f, g){
    res <- c(replicate(3, f()), g()) 
    message(paste("[-] f():", paste(res[1:3], collapse = ","), 
                  "g():", res[4], "\n"))
    if(var(res) == 0){
        message(paste("[+] Magic value is ", res[1]))
        return(invisible(res[1]))
    }
    return(fg(f, g))
}

fg(f,g)

[-] f(): 1,1,1 g(): 2 

[-] f(): 1,1,1 g(): 2 

[-] f(): 1,2,2 g(): 1 

[-] f(): 2,1,1 g(): 2 

[-] f(): 1,1,1 g(): 2 

[-] f(): 1,2,2 g(): 1 

[-] f(): 1,1,1 g(): 1 

[+] Magic value is  1
utubun
  • 4,400
  • 1
  • 14
  • 17
0

Here's another example of how you might do this

call_until = function(f, g) {
  while(TRUE) {
    value <- f()
    seen <- 1
    while(seen < 3) {
      next_value <- f()
      if (next_value == value) {
        seen <- seen + 1
      } else {
        value <- next_value
        seen <- 1
      }
    }
    if (value == g()) {
        return(value)
    }
  }
}

Though it kind of matters if you are supposed to draw three new f values if g doesn't match or just one new value.

Here are some useful testing functions. They just return values from a vector in order, repeating as necessary.

cycler <- function(vals) {
  i <- 1
  function() {
    i<<-i+1
    vals[(i-2) %% length(vals)+1]
  }
}

f <- cycler(c(1,2,2,2,3,4,5,5,5,1,1))
g <- cycler(c(5,4))

With this we get

call_until(f, g)
# [1] 5
MrFlick
  • 195,160
  • 17
  • 277
  • 295