Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function using ifelse not returning a vector in R

Tags:

r

if-statement

I wrote a somewhat grotesque function, which should simply return a vector with two values.

For example, if you put in 33, you should get back c(30, 40). It couldn't get much simpler than this.

return_a_range <- function(number){
    ans <-  ifelse(  (30  <= number & number <= 40), c(30, 40),
                     (ifelse( (40  < number  & number  <= 50), c(40, 50),
                              (ifelse( (50  < number  & number  <= 60), c(50, 60),
                                       (ifelse( (60  < number  & number  <= 70), c(60, 70),
                                                (ifelse( (70  < number  & number  <= 80), c(70, 80),
                                                         (ifelse( (80  < number  & number  <= 100), c(80, 100),                      
                                                                           ans <- c("NA"))))))))))))
    return(ans)}

return_a_range(33)

Why is this returning only 30? How am I not getting back c(30, 40)? Why did R decide to only return the value in the first position of the vector?

EDIT
Although most of the responses are concerned with (justifiably!) spanking me for writing a lousy ifelse statement, I think the real question was recognized and answered best by @MrFick in the comments directly below.

like image 237
tumultous_rooster Avatar asked Mar 18 '23 13:03

tumultous_rooster


2 Answers

You could just use:

> c(floor(33 / 10), ceiling(33 / 10))*10
[1] 30 40

Or as a function - thanks to @Khashaa for a nice modification (in the comments):

f <- function(x) if(abs(x) >= 100) NA else c(floor(x / 10), floor(x/10) + 1)*10
f(44)
#[1] 40 50

f(40)
#[1] 40 50

This kind of functions will be a lot more efficient than multiple nested ifelses.


I overlooked initially that you want to return 30 - 40 for a input value of 40 (I thought you wanted 40 - 50 which is what the above function does).

So this is a slightly more elaborate function which should implement that behavior:

ff <- function(x) {
  if (abs(x) >= 100L) {
    NA 
  } else {
    y <- floor(x / 10L) * 10L
    if (x %% 10L == 0L) {
      c(y - 10L, y) 
    } else {
      c(y, y + 10L)
    }
  }
}

And in action:

ff(40)
#[1] 30 40
ff(45)
#[1] 40 50

Or if you had a vector of numbers you could lapply/sapply over it:

( x <- sample(-100:100, 3, F) )
#[1]  73  89 -97

lapply(x, ff)
#[[1]]
#[1] 70 80
#
#[[2]]
#[1] 80 90
#
#[[3]]
#[1] -100  -90

Or

sapply(x, ff)
#     [,1] [,2] [,3]
#[1,]   70   80 -100
#[2,]   80   90  -90
like image 87
talat Avatar answered Mar 20 '23 16:03

talat


Here's another variation using %/% which will work for f2(40) case too (but my fail somewhere else?)

f2 <- function(x) if(abs(x) >= 100) NA else c(x %/% 10, (x + 10) %/% 10) * 10
f2(40)
## [1] 40 50
like image 37
David Arenburg Avatar answered Mar 20 '23 14:03

David Arenburg