I am using ifelse with pipe in a scenario where I use the forwarded result in both the condition and ifelse branches. The below is a simplified version: it seems that ifelse + pipe only handles condition different from .
if put inside curly braces.
library("magrittr")
FALSE %>% ifelse(., 'true', 'false')
#> [1] "false"
FALSE %>% ifelse(. == TRUE, 'true', 'false')
#> Error in ifelse(., . == TRUE, "true", "false"): unused argument ("false")
FALSE %>% {ifelse(. == TRUE, 'true', 'false')}
#> [1] "false"
My original goal:
library("magrittr")
NULL %>% ifelse(is.null(.), "", as.character(.))
#> Error in ifelse(., is.null(.), "", as.character(.)): unused argument (as.character(.))
NULL %>% {ifelse(is.null(.), "", as.character(.))}
#> [1] ""
Using {}
is good enough for me but I would like to understand the reasons for this behavior.
Edit:
Although this question discusses a related topic and I originally see the idea of putting ifelse inside curly braces there there is no differentiation between using simply .
or using .
in a expression / function call which is the main point of my question.
I think the error message is quite clear.
When you use {}
, the .
in the {}
is substituted to the left-hand-side of %>%
.
When you call a function without {}
, the first argument is the lhs, while the other parameters you coded explicitly will move right, and in addition (see here):
LHS is needed at a position other than the first, one can use the dot,'.', as placeholder.
Therefore, FALSE %>% ifelse(. == TRUE, 'true', 'false')
is actually calling:
ifelse(FALSE, FALSE == TRUE, 'true', 'false')
and FALSE %>% {ifelse(. == TRUE, 'true', 'false')}
is actually calling:
ifelse(FALSE == TRUE, 'true', 'false')
The magrittr
documentation says that when the dot is used in a nested function calls that it behaves as you saw.
Using the dot for secondary purposes
Often, some attribute or property of lhs is desired in the rhs call in addition to the value of lhs itself, e.g. the number of rows or columns. It is perfectly valid to use the dot placeholder several times in the rhs call, but by design the behavior is slightly different when using it inside nested function calls. In particular, if the placeholder is only used in a nested function call, lhs will also be placed as the first argument! The reason for this is that in most use-cases this produces the most readable code.
For example,iris %>% subset(1:nrow(.) %% 2 == 0)
is equivalent toiris %>% subset(., 1:nrow(.) %% 2 == 0)
but slightly more compact. It is possible to overrule this behavior by enclosing the rhs in braces. For example,1:10 %>% {c(min(.), max(.))} is equivalent to c(min(1:10), max(1:10))
.
So the solution that is recommened is actually to use the curly braces as you have already found.
The logical evaluation seems to be a seperate function call within the ifelse
and therefore the reason that it's behaving as such.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With