Reputation: 813
I have a simple question: I have got two functions. Both of them use
if(...) {expression}
if(...) {expression}
if(...) {expression}
instead of
if(...) {expression}
else{
if(...) {expression}
else {expression}
}
But only the one of both works.
The first one works perfectly:
test.1 <- function (y) {
if(y == 1){z <- 10}
if(y == 2){z <- 20}
if(y == 5){z <- 50}
return(z)
}
The second one does not work:
df.1 <- data.frame(A = 1:3)
df.2 <- data.frame(A = 4:6)
df.3 <- data.frame(A = 7:9)
test.2 <- function (num) {
x <- with(if(num == 1){df.1}
if(num == 2){df.2}
if(num == 3){df.3}, {sum(A)})
return(x)
}
I need to use the if else expressions in order to get the second function work:
test.2 <- function (num) {
x <- with(if(num == 1){df.1}
else {if(num == 2){df.2}
else {df.3}
}, {sum(A)})
return(x)
}
I really do not understand why this multiple if statement work in the first case but not in the second one!??
Upvotes: 1
Views: 491
Reputation: 121077
Two problems: Firstly, with
expects a single expression (that evaulates to a data.frame or environment) in its first argument. You can fix that by wrapping those if
statements in curly braces to make it a single expression.
test.2 <- function (num) {
x <- with(
{
if(num == 1){df.1}
if(num == 2){df.2}
if(num == 3){df.3}
},
sum(A)
)
return(x)
}
The second problem is that you aren't returning from the expression after you find a match. So when num
is 1, the first if condition is met and the df.1
is returned. But then the next if
expression is evaulated, and since num
isn't 2, NULL
is returned. Similarly, the third if
expression returns NULL
. Since that is the last expression in the block, that's what gets returned. You effectively have
with(NULL, sum(A))
which is the same as simply sum(A)
, which throws an error because A
doesn't exist.
You could make another fix like
test.2 <- function (num) {
x <- with(
{
if(num == 1)return(df.1)
if(num == 2)return(df.2)
if(num == 3)return(df.3)
},
sum(A)
)
return(x)
}
(this works when num
is 1, 2 or 3 ) but you are much better off using switch
instead, like James suggests.
If all your data frames are consistently named, as in the example, then there's an even better solution than using switch
. Use paste
to get the variable name, then call get
.
test.3 <- function(num) with(get(paste("df", num, sep = ".")), sum(A))
test.3(1) #6
test.3(2) #15
test.3(3) #24
Upvotes: 1
Reputation: 176648
The second example doesn't work because the first argument to with
is supposed to be "an environment, a list, a data frame, or an integer as in sys.call
" (see the Arguments section ?with
).
You can avoid the "unexpected end of line" error by wrapping the if statements in curly brackets:
test.2 <- function (num) {
x <- with({if(num == 1)df.1
if(num == 2)df.2
if(num == 3)df.3}, {sum(A)})
return(x)
}
But this still won't work because you have 3 expressions inside the brackets and only the last evaluated expression will be returned. Well, it will work if num==3
... but we can do better. You could use switch
here instead:
test.2 <- function (num) {
with(switch(num, df.1, df.2, df.3), sum(A))
}
Upvotes: 4
Reputation: 66834
You might be better off using switch
:
test.2 <- function(num){
x <- with(switch(num,df.1,df.2,df.3),{sum(A)})
return(x)
}
test.2(1)
[1] 6
test.2(2)
[1] 15
test.2(3)
[1] 24
Upvotes: 1
Reputation: 13872
it's possible that all three expression
s execute.
if(...) {expression}
if(...) {expression}
if(...) {expression}
In below case, only one expression
will execute.
if(...) {expression}
else
{
if(...) {expression}
else
{
expression
}
}
Upvotes: 0