Search code examples
rfunctionloopsif-statement

Saving output from a function containing loop and ifelse


Basically I wan to be able to save a function output in numeric format into an R object. The function contains a loop and ifelse arguments which may contribute to my difficulties in achieving this.

I would like to create a function like the following:

fnct <- function(x, y) {
  for (i in x) {
    ifelse(i >= y[1] & i <= y[2], y[3], 
            ifelse(i < y[1], y[1], 
                    ifelse((max(x) - y[2] > y[1]), y[2], 
                           NA)))
  }
}

If I run this code, nothing happens.

fnct(c(1:150), c(20, 80, 50)) 

If I modify the code as follows by adding print arguments, I get an ouptut:

fnct <- function(x, y) {
  for (i in x) {
    ifelse(i >= y[1] & i <= y[2],
            print(y[3]),
            ifelse(i < y[1],
                    print(y[1]), ifelse((max(x) - y[2] > y[1]),
                                        print(y[2]),
                                        print(NA))))
  }
}

But I cannot save it to an r object.

I have also tried the following:

fnct <- function(x, y) {
  res <- matrix(nrow=length(x))
  for (i in x) {
    ifelse(i >= y[1] & i <= y[2],
            res[i] <- (y[3]),
            ifelse(i<y[1],
                   res[i] <- (y[1]), ifelse((max(x) - y[2] > y[1]),
                                           res[i] <- (y[2]),
                                           res[i] <- (NA))))
  }
  return(res)
}

which works in this case:

fnct(c(1:150), c(20, 80, 50)) 

but not for this:

fnct(seq(1.575, 5.125, by=0.05), c(1.5, 3, 3.5))

Solution

  • 1. With a for loop.

    You must create a vector where you save the ifelse results.
    Also, note that the question's last ifelse does not depend on the index so it can be pre-computed.

    fnct <- function(x,y) {
      out <- numeric(length(x))
      pre_comp <- ifelse(max(x) - y[2] > y[1], y[2], NA)
      for (i in seq_along(x)) {
        out[i] <- ifelse (x[i] >= y[1] & x[i] <= y[2],
                y[3],
                ifelse (x[i] < y[1],
                        y[1], pre_comp))
      }
      out
    }
    fnct(c(1:150),c(20,80,50))
    #>   [1] 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 50 50 50 50 50 50
    #>  [26] 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50
    #>  [51] 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50
    #>  [76] 50 50 50 50 50 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    #> [101] 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    #> [126] 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    

    Created on 2024-04-12 with reprex v2.1.0


    2. With a *apply loop

    The loop but with a *apply function becomes simpler, there is no need to create the results vector beforehand.

    fnct <- function(x, y) {
      pre_comp <- ifelse(max(x) - y[2] > y[1], y[2], NA)
      sapply(x, \(xx) {
        ifelse (xx >= y[1] & xx <= y[2],
                y[3],
                ifelse (xx < y[1],
                        y[1], pre_comp))
      })
    }
    fnct(c(1:150),c(20,80,50))
    #>   [1] 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 50 50 50 50 50 50
    #>  [26] 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50
    #>  [51] 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50
    #>  [76] 50 50 50 50 50 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    #> [101] 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    #> [126] 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    

    Created on 2024-04-12 with reprex v2.1.0


    Edit

    Following user @lotus's comment I realized that the loop is not needed at all.

    fnct <- function(x, y) {
      ifelse (x >= y[1] & x <= y[2],
              y[3],
              ifelse (x < y[1],
                      y[1], 
                      ifelse(max(x) - y[2] > y[1], 
                             y[2], NA)))
    }
    fnct(c(1:150),c(20,80,50))
    #>   [1] 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 50 50 50 50 50 50
    #>  [26] 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50
    #>  [51] 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50
    #>  [76] 50 50 50 50 50 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    #> [101] 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    #> [126] 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
    

    Created on 2024-04-12 with reprex v2.1.0