Reputation: 43450
I've found R's ifelse statements to be pretty handy from time to time. For example:
ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2
But I'm somewhat confused by the following behavior.
ifelse(TRUE,c(1,2),c(3,4))
# [1] 1
ifelse(FALSE,c(1,2),c(3,4))
# [1] 3
Is this a design choice that's above my paygrade?
Upvotes: 159
Views: 56877
Reputation: 148
Found on everydropr:
ifelse(rep(TRUE, length(c(1,2))), c(1,2),c(3,4))
#>[1] 1 2
Can replicate the result of your condition to return the desired length
Upvotes: 0
Reputation: 8940
In your case, using if_else
from dplyr
would have been helpful: if_else
is more strict than ifelse
, and throws an error for your case:
library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2
Upvotes: 2
Reputation: 77
Here is an approach similar to that suggested by Cath, but it can work with existing pre-assigned vectors
It is based around using the get()
like so:
a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2
Upvotes: 4
Reputation: 4877
The documentation for ifelse
states:
ifelse
returns a value with the same shape astest
which is filled with elements selected from eitheryes
orno
depending on whether the element oftest
isTRUE
orFALSE
.
Since you are passing test values of length 1, you are getting results of length 1. If you pass longer test vectors, you will get longer results:
> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4
So ifelse
is intended for the specific purpose of testing a vector of booleans and returning a vector of the same length, filled with elements taken from the (vector) yes
and no
arguments.
It is a common confusion, because of the function's name, to use this when really you want just a normal if () {} else {}
construction instead.
Upvotes: 129
Reputation: 24074
Note that you can circumvent the problem if you assign the result inside the ifelse
:
ifelse(TRUE, a <- c(1,2), a <- c(3,4))
a
# [1] 1 2
ifelse(FALSE, a <- c(1,2), a <- c(3,4))
a
# [1] 3 4
Upvotes: 17
Reputation: 8377
Sometimes the user just needs a switch
statement instead of an ifelse
. In that case:
condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2
(which is another syntax option of Ken Williams's answer)
Upvotes: 4
Reputation: 24005
I bet you want a simple if
statement instead of ifelse
- in R, if
isn't just a control-flow structure, it can return a value:
> if(TRUE) c(1,2) else c(3,4)
[1] 1 2
> if(FALSE) c(1,2) else c(3,4)
[1] 3 4
Upvotes: 82
Reputation: 9794
yeah, I think ifelse() is really designed for when you have a big long vector of tests and want to map each to one of two options. For example, I often do colors for plot() in this way:
plot(x,y, col = ifelse(x>2, 'red', 'blue'))
If you had a big long vector of tests but wanted pairs for outputs, you could use sapply()
or plyr
's llply()
or something, perhaps.
Upvotes: 9