If-Else/Function Debugging - r

R beginner here. I'm trying to create a function that converts values for a list in R using if-else. I'm pretty sure I'm violating some cardinal rule(s) with syntax/logic in R and I've read several manuals/online help tools for functions and if/else statements, but I cannot identify what I'm doing wrong. Here's what I am working with:
convTemp <- function(vector, to="Celsius"){
if (to = "Celsius" ) {
return (vector - 32) * 5/9
}
else
print (vector)
}
Any help/suggestions appreciated. Thanks.

You don't even need to define a function for this, just use base R's ifelse():
temp_in_celsius <- ifelse(to == "Celsius", (vector - 32) * 5/9, vector)
As for what you are doing wrong, to = "Celsius" is an assignment, not an equality expression. You probably intended to do if (to == "Celsius") {...}.

In R, checking equality requires two equal signs "==".
Change the if statement to the following:
if (to == "Celsius" )

Related

What is the consistency steps of a recursive function?

I am finding inconsistency in recursive function examples, so I need help clarifying its workings.
This recursive function has the argument x value be returned along with function fracrec. This fracrec gets multiplied by the original value of x. The value of it is whatever the parenthesis gives x-1 . It repeats until it exits at x == 0. Meaning that the x portion and '*' of return is the "formula" and what is used for every round.
facrec <- function(x){
if(x==0){
return(1)
} else {
return(x*facrec(x-1))
}
}
Now take this next one and there isn't anything like x and ''. So I then look at it differently since myfibrec(5) gives '5'. Taking the absolute value of the first pass would be 4+3 and already surpassing 5 with more passes still to go. There isn't any formula to go off of, so I am having difficulty understanding how the 5 came about. In the above I used the formula to be 'x' and '', which I'll admit its odd and probably incorrect.
myfibrec <- function(n) {
if(n==1||n==2){
return(1)
}else{
return(myfibrec(n-1)+myfibrec(n-2))
}
}
In yet another one, below it treats the value in the argument as the formula. This gives 2,3,4,5,6,7,8,9,10.
function Count (integer N)
if (N <= 0) return "Must be a positive integer";
if (N >9 ) return "counting completed";
else return Count (N+1);
end function
Where are all the formulas or math calculations coming from in these recursive functions?
for 'facrec' google "factorial"
for 'myfibrec' google "Fibonacci"
last one seems to be java code, not R

Why does my function in R keep reading my argument as a function?

When I create a user-defined function in RStudio, or even just have a for loop, it keeps returning this error:
p <- NEQ1data$P.inv.
for(value in p){
sem <- sqrt(value(1-value)/10000)
return(sem)
}
Error: could not find function "value"
Similarly, when I try a to define this function:
se_fyp <- function(a){
sem<-sqrt(a(1-a)/10000)
return(se)
}
And have the input "NEQ(1)$P.inv." it says that it cannot find "function a".
I'm teaching myself R, and have yet to find any information on this issue.I believe that I am following the standard function format.
Thank you in advance!
When you write
sqrt( value( 1-value ) / 10000)
You're trying to call value like a function. Look at the similarity to the call to sqrt. I added spacing here for emphasis.
No language that I know of allows for "implicit multiplication". You need to explicitly write the *
sqrt( value * ( 1-value ) / 10000)

R recursive function call that works without stating arguments to function

The following simple recursion finds duplicated elements in a vector. It's taken from chapter 2 Functional Programming in R: Advanced Statistical Programming for Data Science, Analysis and Finance by Thomas Mailund. I wonder why it works when we call rest inside the function as it is calling a function without stating arguments.
Usually this would just return the function definition, but in the recursive function we don't need to and I wondered why.
I can see how this would work if we replaced rest in the function directly with find_duplicates(x, i + 1), but I am struggling to see why it works calling just the name which the function is attached to.
E.g if we define f<- function (x) x and call f it just returns the code function (x) x.
find_duplicates <- function(x, i = 1) {
if (i >= length(x)) return(c())
rest <- find_duplicates(x, i + 1)
if (x[i] == x[i + 1]) c(i, rest)
else rest
}
rest is not a function, it's the output of the function find_duplicates given arguments x and i+1.
So indeed it's the same to type rest or find_duplicates(x, i + 1) in the if clause, they're both values, not functions.

Stop function evaluation using another function in R

I did a test with nested return function in R, but without success. I came from Mathematica, where this code works well. Here is a toy code:
fstop <- function(x){
if(x>0) return(return("Positive Number"))
}
f <- function(x){
fstop(x)
"Negative or Zero Number"
}
If I evaluate f(1), I get:
[1] "Negative or Zero Number"
When I expected just:
[1] "Positive Number"
The question is: there is some non-standard evaluation I can do in fstop, so I can have just fstop result, without change f function?
PS: I know I can put the if direct inside f, but in my real case the structure is not so simple, and this structure would make my code simpler.
Going to stick my neck out and say...
No.
Making a function return not to its caller but to its caller's caller would involve changing its execution context. This is how things like return and other control-flow things are implemented in the source. See:
https://github.com/wch/r-source/blob/trunk/src/main/context.c
Now, I don't think R level code has access to execution contexts like this. Maybe you could write some C level code that could do it, but its not clear. You could always write a do_return_return function in the style of do_return in eval.c and build a custom version of R... Its not worth it.
So the answer is most likely "no".
I think Spacedman is right, but if you're willing to evaluate your expressions in a wrapper, then it is possible by leveraging the tryCatch mechanism to break out of the evaluation stack.
First, we need to define a special RETURN function:
RETURN <- function(x) {
cond <- simpleCondition("") # dummy message required
class(cond) <- c("specialReturn", class(cond))
attr(cond, "value") <- x
signalCondition(cond)
}
Then we re-write your functions to use our new RETURN:
f <- function(x) {
fstop(x)
"Negative or Zero"
}
fstop <- function(x) if(x > 0) RETURN("Positive Number") # Note `RETURN` not `return`
Finally, we need the wrapper function (wsr here stands for "with special return") to evaluate our expressions:
wsr <- function(x) {
tryCatch(
eval(substitute(x), envir=parent.frame()),
specialReturn=function(e) attr(e, "value")
) }
Then:
wsr(f(-5))
# [1] "Negative or Zero"
wsr(f(5))
# [1] "Positive Number"
Obviously this is a little hacky, but in day to day use would be not much different than evaluating expressions in with or calling code with source. One shortcoming is this will always return to the level you call wsr from.

if-else vs ifelse with lists

Why do the if-else construct and the function ifelse() behave differently?
mylist <- list(list(a=1, b=2), list(x=10, y=20))
l1 <- ifelse(sum(sapply(mylist, class) != "list")==0, mylist, list(mylist))
l2 <-
if(sum(sapply(mylist, class) != "list") == 0){ # T: all list elements are lists
mylist
} else {
list(mylist)
}
all.equal(l1,l2)
# [1] "Length mismatch: comparison on first 1 components"
From the ifelse documentation:
‘ifelse’ returns a value with the same shape as ‘test’ which is
filled with elements selected from either ‘yes’ or ‘no’ depending
on whether the element of ‘test’ is ‘TRUE’ or ‘FALSE’.
So your input has length one so the output is truncated to length 1.
You can also see this illustrated with a more simple example:
ifelse(TRUE, c(1, 3), 7)
# [1] 1
if ( cond) { yes } else { no } is a control structure. It was designed to effect programming forks rather than to process a sequence. I think many people come from SPSS or SAS whose authors chose "IF" to implement conditional assignment within their DATA or TRANSFORM functions and so they expect R to behave the same. SA and SPSS both have implicit FOR-loops in there Data steps. Whereas R came from a programming tradition. R's implicit for-loops are built in to the many vectorized functions (including ifelse). The lapply/sapply fucntions are the more Rsavvy way to implement most sequential processing, although they don't succeed at doing lagged variable access, especially if there are any randomizing features whose "effects" get cumulatively handled.
ifelse takes an expression that builds a vector of logical values as its first argument. The second and third arguments need to be vectors of equal length and either the first of them or the second gets chosen. This is similar to the SPSS/SAS IF commands which have an implicit by-row mode of operation.
For some reason this is marked as a duplicate of
Why does ifelse() return single-value output?
So a work around for that question is:
a=3
yo <- ifelse(a==1, 1, list(c(1,2)))
yo[[1]]

Resources