Topic |
Magrittr 2.0.3
|
Base 4.3.0
|
Operator |
%>% %<>% %$% %!>% %T>%
|
|> (since 4.1.0) |
Function call |
1:3 %>% sum() |
1:3 |> sum() |
|
1:3 %>% sum |
Needs brackets / parentheses |
|
1:3 %>% `+`(4) |
Some functions are not supported |
Insert on first empty place |
mtcars %>% lm(formula = mpg ~ disp) |
mtcars |> lm(formula = mpg ~ disp) |
Placeholder |
. |
_ (since 4.2.0) |
|
mtcars %>% lm(mpg ~ disp, data = . ) |
mtcars |> lm(mpg ~ disp, data = _ ) |
|
mtcars %>% lm(mpg ~ disp, . ) |
Needs named argument |
|
1:3 %>% setNames(., .) |
Can only appear once |
|
1:3 %>% {sum(sqrt(.))} |
Nested calls are not allowed |
Extraction call |
mtcars %>% .$cyl mtcars %>% {.$cyl[[3]]} or mtcars %$% cyl[[3]]
|
mtcars |> _$cyl (since 4.3.0) mtcars |> _$cyl[[3]]
|
Environment |
%>% has additional function environment use:"x" %!>% assign(1)
|
"x" |> assign(1) |
Create Function |
top6 <- . %>% sort() %>% tail() |
Not possible |
Speed |
Slower because Overhead of function call
|
Faster because Syntax transformation
|
使用时许多差异和限制就会消失|>
与(匿名)函数结合使用:
1 |> (\(.) .)()
-3:3 |> (\(.) sum(2*abs(.) - 3*.^2))()
另请看一下:如何纯粹在基础 R 中进行管道传输(“基础管道”)? https://stackoverflow.com/questions/65329335 and 五种 Magrittr 管道 %>%、%%、%$%、%!>% 和 %T>% 的区别和用例是什么? https://stackoverflow.com/questions/76326742.
需要括号
library(magrittr)
1:3 |> sum
#Error: The pipe operator requires a function call as RHS
1:3 |> sum()
#[1] 6
1:3 |> approxfun(1:3, 4:6)()
#[1] 4 5 6
1:3 %>% sum
#[1] 6
1:3 %>% sum()
#[1] 6
1:3 %>% approxfun(1:3, 4:6) #But in this case empty parentheses are needed
#Error in if (is.na(method)) stop("invalid interpolation method") :
1:3 %>% approxfun(1:3, 4:6)()
#[1] 4 5 6
Some 功能 are not 支持的 https://github.com/wch/r-source/blob/e3b297a64f932d402dc59727c088386cae6a8112/src/main/names.c#L1007,
但有些仍然可以通过将它们放在括号中来调用,通过函数调用它们::
,使用占位符,在函数中调用它或定义函数的链接。
1:3 |> `+`(4)
#Error: function '+' not supported in RHS call of a pipe
1:3 |> (`+`)(4)
#[1] 5 6 7
1:3 |> base::`+`(4)
#[1] 5 6 7
1:3 |> `+`(4, e2 = _)
#[1] 5 6 7
1 |> (`+`)(2) |> (`*`)(3) #(1 + 2) * 3 or `*`(`+`(1, 2), 3) and NOT 1 + 2 * 3
#[1] 9
1:3 |> (\(.) . + 4)()
#[1] 5 6 7
fun <- `+`
1:3 |> fun(4)
#[1] 5 6 7
1:3 %>% `+`(4)
#[1] 5 6 7
占位符需要命名参数
2 |> setdiff(1:3, _)
#Error: pipe placeholder can only be used as a named argument
2 |> setdiff(1:3, y = _)
#[1] 1 3
2 |> (\(.) setdiff(1:3, .))()
#[1] 1 3
2 %>% setdiff(1:3, .)
#[1] 1 3
2 %>% setdiff(1:3, y = .)
#[1] 1 3
也适用于可变参数函数...
(dot-dot-dot) 参数,占位符_
需要用作命名参数。
"b" |> paste("a", _, "c")
#Error: pipe placeholder can only be used as a named argument
"b" |> paste("a", . = _, "c")
#[1] "a b c"
"b" |> (\(.) paste("a", ., "c"))()
#[1] "a b c"
占位符可以只出现一次
1:3 |> setNames(nm = _)
#1 2 3
#1 2 3
1:3 |> setNames(object = _, nm = _)
#Error in setNames(object = "_", nm = "_") :
# pipe placeholder may only appear once
1:3 |> (\(.) setNames(., .))()
#1 2 3
#1 2 3
1:3 |> list() |> setNames(".") |> with(setNames(., .))
#1 2 3
#1 2 3
1:3 |> list(. = _) |> with(setNames(., .))
#1 2 3
#1 2 3
1:3 %>% setNames(object = ., nm = .)
#1 2 3
#1 2 3
1:3 %>% setNames(., .)
#1 2 3
#1 2 3
嵌套调用不允许
1:3 |> sum(sqrt(x=_))
#Error in sum(1:3, sqrt(x = "_")) : invalid use of pipe placeholder
1:3 |> (\(.) sum(sqrt(.)))()
#[1] 4.146264
1:3 %>% {sum(sqrt(.))}
#[1] 4.146264
提取呼叫
自 4.3.0 起的实验性功能。占位符_
现在也可以用于前向管道的右侧|>
表达式作为提取调用中的第一个参数,例如_$coef
。更一般地,它可以用作提取链的头部,例如_$coef[[2]]
*
mtcars |> _$cyl
mtcars |> _[["cyl"]]
mtcars |> _[,"cyl"]
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars |> _$cyl[[4]]
#[1] 6
mtcars %>% .$cyl
mtcars %>% .[["cyl"]]
mtcars %>% .[,"cyl"]
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
#mtcars %>% .$cyl[4] #gives mtcars[[4]]
mtcars %>% .$cyl %>% .[4]
#[1] 6
No 附加环境
assign("x", 1)
x
#[1] 1
"x" |> assign(2)
x
#[1] 2
"x" |> (\(x) assign(x, 3))()
x
#[1] 2
1:3 |> assign("x", value=_)
x
#[1] 1 2 3
"x" %>% assign(4)
x
#[1] 1 2 3
4 %>% assign("x", .)
x
#[1] 1 2 3
"x" %!>% assign(4) #Use instead the eager pipe
x
#[1] 4
5 %!>% assign("x", .)
x
#[1] 5
创建一个函数
top6 <- . %>% sort() %>% tail()
top6(c(1:10,10:1))
#[1] 8 8 9 9 10 10
其他可能性:
不同的管道操作符和不同的占位符可以通过以下方式实现奇异烟斗 ->.;
什么不是管道(参见缺点 https://stackoverflow.com/q/67868289/10488504) 正在覆盖.
1:3 ->.; sum(.)
#[1] 6
mtcars ->.; .$cyl
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars ->.; .$cyl[4]
#[1] 6
1:3 ->.; setNames(., .)
#1 2 3
#1 2 3
1:3 ->.; sum(sqrt(x=.))
#[1] 4.146264
"x" ->.; assign(., 5)
x
#[1] 5
6 ->.; assign("x", .)
x
#[1] 6
1:3 ->.; . + 4
#[1] 5 6 7
1 ->.; (`+`)(., 2) ->.; (`*`)(., 3)
#[1] 9
1 ->.; .+2 ->.; .*3
#[1] 9
并且评价不同。
x <- data.frame(a=0)
f1 <- \(x) {message("IN 1"); x$b <- 1; message("OUT 1"); x}
f2 <- \(x) {message("IN 2"); x$c <- 2; message("OUT 2"); x}
x ->.; f1(.) ->.; f2(.)
#IN 1
#OUT 1
#IN 2
#OUT 2
# a b c
#1 0 1 2
x |> f1() |> f2()
#IN 2
#IN 1
#OUT 1
#OUT 2
# a b c
#1 0 1 2
f2(f1(x))
#IN 2
#IN 1
#OUT 1
#OUT 2
# a b c
#1 0 1 2
或者定义一个自定义管道运算符这是设置.
到新环境中的左旋值(lhs)的值并评估其中的右旋值(rhs)。但这里无法创建或更改调用环境中的值。
`:=` <- \(lhs, rhs) eval(substitute(rhs), list(. = lhs))
mtcars := .$cyl[4]
#[1] 6
1:3 := setNames(., .)
#1 2 3
#1 2 3
1:3 := sum(sqrt(x=.))
#[1] 4.146264
"x" := assign(., 6)
x
#Error: object 'x' not found
1 := .+2 := .*3
#[1] 9
所以另一个尝试是将 lhs 分配给占位符.
在调用环境中并评估调用环境中的 rhs。但在这儿.
如果它已经存在,将从调用环境中删除。
`?` <- \(lhs, rhs) {
on.exit(if(exists(".", parent.frame())) rm(., envir = parent.frame()))
assign(".", lhs, envir=parent.frame())
eval.parent(substitute(rhs))
}
mtcars ? .$cyl[4]
#[1] 6
1:3 ? setNames(., .)
#1 2 3
#1 2 3
1:3 ? sum(sqrt(x=.))
#[1] 4.146264
"x" ? assign(., 6)
x
#[1] 6
1 ? .+2 ? .*3
#[1] 9
另一种可能性是更换所有.
与 lhs 以便在评估期间.
不再作为名称存在。
`%|>%` <- \(lhs, rhs)
eval.parent(eval(call('substitute', substitute(rhs), list(. = lhs))))
mtcars %|>% .$cyl[4]
[1] 6
1:3 %|>% setNames(., .)
1 2 3
1 2 3
1:3 %|>% sum(sqrt(x=.))
[1] 4.146264
"x" %|>% assign(., 6)
x
#[1] 6
1 %|>% .+2 %|>% .*3
#[1] 7
所使用的运算符的名称会影响运算符的优先级:请参阅相同的函数,但使用名称 %>% 会导致与使用名称 := 时不同的结果 https://stackoverflow.com/questions/76155705.
有关更高级的选项,请参阅:编写自己的/自定义的管道运算符 https://stackoverflow.com/questions/76160601.
Speed
library(magrittr)
`:=` <- \(lhs, rhs) eval(substitute(rhs), list(. = lhs))
`?` <- \(lhs, rhs) {
on.exit(if(exists(".", parent.frame())) rm(., envir = parent.frame()))
assign(".", lhs, envir=parent.frame())
eval.parent(substitute(rhs))
}
`%|>%` <- \(lhs, rhs)
eval.parent(eval(call('substitute', substitute(rhs), list(. = lhs))))
x <- 42
bench::mark(min_time = 0.2, max_iterations = 1e8
, x
, identity(x)
, "|>" = x |> identity()
, "|> _" = x |> identity(x=_)
, "->.;" = {x ->.; identity(.)}
, "|> f()" = x |> (\(y) identity(y))()
, "%>%" = x %>% identity
, ":=" = x := identity(.)
, "list." = x |> list() |> setNames(".") |> with(identity(.))
, "%|>%" = x %|>% identity(.)
, "?" = x ? identity(.)
)
Result
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl>
1 x 31.08ns 48.2ns 19741120. 0B 7.46 2646587 1
2 identity(x) 491.04ns 553.09ns 1750116. 0B 27.0 323575 5
3 |> 497.91ns 548.08ns 1758553. 0B 27.3 322408 5
4 |> _ 506.87ns 568.92ns 1720374. 0B 26.9 320003 5
5 ->.; 725.03ns 786.04ns 1238488. 0B 21.2 233864 4
6 |> f() 972.07ns 1.03µs 929926. 0B 37.8 172288 7
7 %>% 2.76µs 3.05µs 315448. 0B 37.2 59361 7
8 := 3.02µs 3.35µs 288025. 0B 37.0 54561 7
9 list. 5.19µs 5.89µs 166721. 0B 36.8 31752 7
10 %|>% 6.01µs 6.86µs 143294. 0B 37.0 27076 7
11 ? 30.9µs 32.79µs 30074. 0B 31.3 5768 6