Given the following code:
a <- 3
colors <- ifelse(a == 3,
c("#004B93", "#389DC3", "#6DBE99"),
ifelse(a == 2, c("#004B93", "#389DC3"), c("#000000", "#000000", "#000000")))
My expectation ist to get something like
> colors
[1] "#004B93" "#389DC3" "#6DBE99"
But what I get is
> colors
[1] "#004B93"
What am I doing wrong?
CodePudding user response:
You can also use if else statements for check the conditions inside R.
For that you can do the same logic as I checked for you.
a <- 3
colors <- if(a == 3) {
c("#004B93", "#389DC3", "#6DBE99")
} else if (a == 2) {
c("#004B93", "#389DC3")
} else {
c("#000000", "#000000", "#000000")
}
print(colors)
Output Result :
[1] "#004B93" "#389DC3" "#6DBE99"
CodePudding user response:
Here's how I would write this:
possible_colors = list(
c("#000000", "#000000", "#000000"),
c("#004B93", "#389DC3"),
c("#004B93", "#389DC3", "#6DBE99")
)
colors = if (a < 1L || a > 3L) list[[1L]] else list[[a]]
This assumes that a
only has integer values. Adjust the condition of the if
accordingly if that is not the case.
If you know that a
will never be any value except 1, 2 or 3, you can omit the if
completely and directly write colors = possible_colors[[a]]
.
CodePudding user response:
ifelse
is a command that is usually better to avoid.
Why? Because
ifelse(TRUE, 1:3, 4:6)
returns 1
and not 1:3
.
In fact, ifelse
wants the output to be the same length as the test. Above TRUE
is a vector of length 1, while the candidate output1:3
is of length 3. However, ifelse
does not raise any warning, it just cuts the vector 1:3
.
There is rationale behind this, and this example should explain it:
ifelse(c(TRUE, FALSE, TRUE), yes = 1:3, no = 4:6)
[1] 1 5 3
True values are taken from the yes
argument and false values are
taken from the no
argument. If you really want this sophisticate behaviour, ifelse
can be extremely powerful, but this is rarely what you want.
The good news is that R is a functional language, thus everything is a function, including the if/else construct. Hence, to get the intended result from
ret <- ifelse(TRUE, 1:3, 4:6)
rewrite it like so:
ret <- if(TRUE) 1:3 else 4:6
and ret
is 1:3
Do you need nested conditions? No problem.
a <- 1
ret <- if(a == 1) 1:3 else (if(a == 2) 4:6 else 7:9)
The line above emphasises the functional approach, where I replace the expression 4:6
with the bracketed one, but it can be shortened to:
ret <- if(a == 1) 1:3 else if(a == 2) 4:6 else 7:9
However, let me note that for this type of tasks, there is a dedicated R function: switch
.
ret <- switch(a, 1:3, 4:6, 7:9)
Counting after a
, the first, second, etc. argument is chosen depending on the value of a
, thus:
a <- 2
switch(a, 1:3, 4:6, 7:9)
# 4:6
As for your case:
a <- 3
switch(a,
c("#000000", "#000000", "#000000"),
c("#004B93", "#389DC3"),
c("#004B93", "#389DC3", "#6DBE99"))
# [1] "#004B93" "#389DC3" "#6DBE99"