Reputation: 61
Is there a way for a function to detect whether a magrittr pipe has passed data into it?
Certain functions like ifelse()
don't work well with magrittr input.
1:4 %>% ifelse(. < 3, "low", "high")
#> Error in ifelse(., . < 3, "low", "high") : unused argument ("high")
results in an error.
To make the function work as intended, you have to use
1:4 %>% {ifelse(. < 3, "low", "high")}
#> "low" "low" "high" "high"
Is there a way to redefine a function so that it behaves differently when piped into?
my_ifelse <- function(...) {
args <- list(...)
if (sys.call()[[2]] == ".") args <- args[-1]
ifelse(test = args[[1]], yes = args[[2]], no = args[[3]])
}
1:4 %>% my_ifelse(. < 3, "low", "high")
#> "low" "low" "high" "high"
Are there any issues with this solution? Could it break unexpectedly?
Edit: Obviously, this will return an error if an incorrect number of arguments are passed. A more full-fledged approach would attempt to provide informative errors and even potentially allow use argument names rather than ...
Upvotes: 0
Views: 106
Reputation: 388962
When we use pipe we know that the left-hand side of pipe is treated as the first argument to the function on the right-hand side.
So you can't expect this to work :
1:4 %>% ifelse(. < 3, "low", "high")
Since what this actually means is
ifelse(1:4, 1:4 < 3, "low", "high")
which gives you the exact same error
Error in ifelse(1:4, 1:4 < 3, "low", "high") : unused argument ("high")
Yes, you can stop this default behavior by using {}
around pipes.
I am not sure what your final goal is but a general rule which can be followed is all the changes that you want to do on the input should be done on LHS side only unless you want to use {}
.
So this works :
(1:4 < 3) %>% ifelse("low", "high")
#[1] "low" "low" "high" "high"
Upvotes: 2