Home > OS >  How to make magrittr's pipe operator (%>%) work when nesting base-R functions?
How to make magrittr's pipe operator (%>%) work when nesting base-R functions?

Time:08-09

Why does this code produce an error ?

library(magrittr)

c('a', 'b', 'c', 'b') %>% 
  seq_len(length(.))

# Error in seq_len(., length(.)) : 
#   2 arguments passed to 'seq_len' which requires 1

CodePudding user response:

Another way could be to wrap in braces:

c('a', 'b', 'c', 'b') %>% 
  {seq_len(length(.))}

See: https://magrittr.tidyverse.org/reference/pipe.html

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 to iris %>% 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)).

CodePudding user response:

Pipe operator tries to insert left-hand-side argument as an argument to the function call on the right-hand-side. If you are not using any . at the rhs function call as a parameter, it inserts it as a first argument by default. In your situation, since you are not using . directly as an argument to seq_len, it transforms the call into:

seq_len(., length(.))

and I think there is no way around it with nesting.

There is no point in nesting here, however. The main idea behind pipe operator is to avoid nesting, so code more in line with this philosophy would be:

c('a', 'b', 'c', 'b') %>% 
  length() %>%
  seq_len()

EDIT: I feel like I need to add: you can nest . inside some other call here, but you need to pass . as a direct parameter to function on rhs at least once. Here is an example that would work:

1:5 %>%
  purrr::map2(., exp(.), ~ .x   .y) # first parameter is passes as a direct ., second is . nested within a call -- no implicit adding of . as first parameter
  • Related