Home > Back-end >  Improve if else statement
Improve if else statement

Time:05-07

I have the following function in R. It is working fine, however, I think that must be a better way to run this function.

values <- c("a","b")


print <- function(values){
  
  size <- length(values)

  if (size == 1) {
  
  final <- values[1]
  
}else if(size == 2){
  
  final <- paste0(values[2], " and ", values[1])
}else if(size == 3){
  
  final <- paste0(values[3], " and ",values[2], " and ", values[1])
  
}
  return(final)
}
print(values)

The user can change the size of values, so if he choose values <- c("a","b", "c") the function is gonna run in the last condition. However, the last condition is in art equal to the second conditional plus something new. It is possible to make an if statement, or something in those lines that uses the previous condition . Something like:

values <- c("a","b", "c")


print <- function(values){
  
  size <- length(values)

  if (size == 1) {
  
  final <- values[1]
  
}else if(size == 2){
  
  final <- paste0(values[2], " and ", final )
}else if(size == 3){
  
  final <- paste0(values[3], " and ",final )
  
}
  return(final)
}
print(values)

CodePudding user response:

Try this, which reverses the order of the input vector and pastes "and" between:

newfun <- function(x){
  ifelse(length(x)>1, paste(rev(x), collapse = " and "), x)
}

Output:

newfun(letters[1])
 # [1] "a"

newfun(letters[1:2])]
 # [1] "b and a"

# and so on...

newfun(letters[1:5])
 # [1] "e and d and c and b and a"

Testing this against your function to see if it is identical:

all.equal(print(letters[1:3]), 
          newfun(letters[1:3]))
# [1] TRUE

I would also strongly caution naming user-defined functions names that are already inherent in R (i.e. print() is already a function in R.

CodePudding user response:

Another way of reversing the order of the vectors:

reverse_print <- function(values) paste(values[order(values, decreasing = TRUE)], collapse = " and ")

reverse_print(c("a", "b"))
#[1] "b and a"

reverse_print(c("a", "b", "c", "d"))
#[1] "d and c and b and a"

However, if your main objective is to create a function that recursively uses a condition and the previous conditions, one way of achieving it is to create a direct recursive function, in which the function calls itself (please see @G.Chan's comment for reference). Unfortunately, I failed to create such function for your case. Error: C stack usage 15927520 is too close to the limit was produced. This kind of error is relatively common in recursive functions, as discussed here.

Instead of crating a direct recursive function, I would suggest making the use of while along with incremented index as follows:

revprint <- function(values) {
  size   <- length(values)
  if (size == 1) {
    cat(values[1])
  } else {
    while (size > 1) {
      final    <- values[size]
      appended <- paste0(final, " and ")
      size     <- size - 1
      output   <- cat(appended)
    }
    cat(output, values[1], sep = "")
  }
}

revprint("a")
# a

revprint(c("a", "b", "c", "d"))
# d and c and b and a

If the length of the input (a character vector) is larger than 1, this function displays the final character of the input using paste0, and then incrementally reduces the length of the input. In each incremental step, the final character of the new (shorter) input is displayed, appended with the final character of the previous (longer) input.

Because this function uses cat, the result is displayed on the console, but it cannot be assigned directly to an object. To assign it to an object, you can use capture.output()

out <- capture.output(revprint(c("a", "b", "c", "d")))
out
#[1] "d and c and b and a"
  • Related