Home > Blockchain >  My R function is returning a vector that is larger than expected
My R function is returning a vector that is larger than expected

Time:10-28

I have an assignment for class that tasks me with creating a function in R that takes in a vector of values and converts them between Fahrenheit, Celsius and Kelvin. The example that I try to run through my code should produce a return vector that contains only 3 values, yet it is returning a vector that holds 26 values.

Here is my code below:

convTemp <- function(x, from = "C", to = "F") {
    newX <- vector("double", length(x))
    if (from == to) {
        warning("Your 'from' parameter is the same as your 'to' parameter!") # From and To are same temperature scale
    }
    if (from == "C" && to == "F") { # Celsius to Fahrenheit
        for (i in x) {
            newX[i] <- ((9/5)*x[i] 32)
        }
    }
    if (from == "C" && to == "K") { # Celsius to Kelvin
        for (i in x) {
            newX[i] <- (x[i] 273.15)
        }
    }
    if (from == "F" && to == "C") { # Fahrenheit to Celsius
        for (i in x) {
            newX[i] <- ((x[i]-32)*(5/9))
        }
    }
    if (from == "K" && to == "C") { # Kelvin to Celsius
        for (i in x) {
            newX[i] <- (x[i]-273.15)
        }
    }
    if (from == "F" && to == "K") { # Fahrenheit to Kelvin
        for (i in x) {
            newX[i] <- ((((x[i]-32)*5)/9) 273.15)
        }
    }
    if (from == "K" && to == "F") { # Kelvin to Fahrenheit
        for (i in x) {
            newX[i] <- ((((x[i]-273.15)*9)/5) 32)
        }
    }
    return(newX)
}

convTemp(c(35,40,45), from="F", to="K")

And here is the output I'm receiving:

 [1]  0  0  0 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[26] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA

So I'm not sure why the function is returning such a large vector of missing values when it should be returning a vector of 3 Kelvin values.

CodePudding user response:

Since R is vectorized, you do not need the for-loops. Check the code below to see how to better write your function:

convTemp <- function(x, from = "C", to = "F") {
  stopifnot(c(from, to) %in% c('C', 'F', 'K'))# IN CASE YOU INPUT A DIFFERENT ARGUMENT OTHER THAN C,F, AND K
  if (from == to) {
    warning("Your 'from' parameter is the same as your 'to' parameter!") # From and To are same temperature scale
  }
  if (from == "C"){
    if (to == "F")  9/5 * x   32 # Celsius to Fahrenheit
    else (x   273.15) # Celsius to Kelvin
  }
  else if (from == "F") { 
    if(to == "C") (x -32) * 5/9 # Fahrenheit to Celsius
    else  (x - 32) * 5/9   273.15 # Fahrenheit to Kelvin
  }
  else { 
    if(to == 'C')(x - 273.15) # Kelvin to Celsius
    else (x-273.15) * 9/5   32 # Kelvin to Fahrenheit
  }
}

convTemp(c(35,40,45), from="F", to="K")
[1] 274.8167 277.5944 280.3722

CodePudding user response:

In the code (assuming it is a coding exercise), we need not loop over the values (for(i in x)) but loop over the sequence (for(i in seq_along(x)))

convTemp <- function(x, from = "C", to = "F") {
    newX <- vector("double", length(x))
    if (from == to) {
        warning("Your 'from' parameter is the same as your 'to' parameter!") # From and To are same temperature scale
    }
    if (from == "C" && to == "F") { # Celsius to Fahrenheit
        for (i in seq_along(x)) {
            newX[i] <- ((9/5)*x[i] 32)
        }
    }
    if (from == "C" && to == "K") { # Celsius to Kelvin
        for (i in seq_along(x)) {
            newX[i] <- (x[i] 273.15)
        }
    }
    if (from == "F" && to == "C") { # Fahrenheit to Celsius
        for (i in seq_along(x)) {
            newX[i] <- ((x[i]-32)*(5/9))
        }
    }
    if (from == "K" && to == "C") { # Kelvin to Celsius
        for (i in seq_along(x)) {
            newX[i] <- (x[i]-273.15)
        }
    }
    if (from == "F" && to == "K") { # Fahrenheit to Kelvin
        for (i in seq_along(x)) {
            newX[i] <- ((((x[i]-32)*5)/9) 273.15)
        }
    }
    if (from == "K" && to == "F") { # Kelvin to Fahrenheit
        for (i in seq_along(x)) {
            newX[i] <- ((((x[i]-273.15)*9)/5) 32)
        }
    }
    return(newX)
}

-testing

> convTemp(c(35,40,45), from="F", to="K")
[1] 274.8167 277.5944 280.3722

CodePudding user response:

Not that you asked, but since @onyambu helped eliminate the for loops, I though I might help eliminate the if statements. I'm not sure if this is more efficient, but I find a bunch of if statements difficult to follow sometimes.

convTemp <- function(x, from = "C", to = "F") {
  stopifnot(c(from, to) %in% c('C', 'F', 'K'))
  
  from. <- c(0,-32,-273.15)[which(c('C', 'F', 'K') %in% from)]
  to. <- c(0,32,273.15)[which( c('C', 'F', 'K') %in% to)]
  mult. <- c(1, 5/9, 9/5 )[sum(which(c(from, to) %in% 'F')) 1]
  
  (x   from.)*mult.   to.
}


convTemp(c(35,40,45), from="F", to="K")
#> [1] 274.8167 277.5944 280.3722
convTemp(c(35,40,45), from="C", to="F")
#> [1]  95 104 113
  • Related