用于 ! (或任何逻辑运算符)与 %>% (magrittr) 产生意外输出
Use of ! (or any logical operator) with %>% (magrittr) produces unexpected output
我有 运行 遇到 %>%
与 !
结合时产生非常令人惊讶的输出的情况。考虑以下代码:
x <- c(1:20)
y <- !is.na(x)
> y
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
> sum(Y)
[1] 20
好的,没什么奇怪的。但是,如果我尝试使用 %>%
来缩短它,就会发生奇怪的事情:
!is.na(x) %>% sum
[1] TRUE
TRUE
??不是我所期望的 - 它应该是 20
。
如果我删除 !
,它会给我预期的 0
:
> is.na(x) %>% sum
[1] 0
如果我添加方括号,它会起作用:
> {!is.na(x)} %>% sum
[1] 20
并将 !
视为函数有效:
> is.na(x) %>% `!` %>% sum
[1] 20
!is.na(x) %>% sum
在做什么,为什么 return TRUE
而不是 20
?
编辑: 其他逻辑运算符产生类似的行为:
> T&T %>% sum()
[1] TRUE
> {T&T} %>% sum()
[1] 1
> T|T %>% sum()
[1] TRUE
> {T|T} %>% sum()
[1] 1
我怀疑是操作顺序问题:
!is.na(x) %>% sum
正在评估
!(is.na(x) %>% sum)
相当于TRUE
尽管我接受了@C-Z_ 的回答,但我想添加另一个来提供相关背景信息。感谢@rawr 指引我前往 ?Syntax
.
基本上 %>%
被认为是一个操作符,就像 %in%
一样,因此它必须遵守操作顺序。在 Syntax
帮助页面上,这对应于 %any%
运算符(即任何中缀运算符),因为用户可以随意定义它们。碰巧的是,这意味着 %>%
在任何逻辑运算符之前触发,也在算术运算符(例如 *
和 \
)之前触发。因此,如果您像我一样天真地认为 %>%
的左侧将在链中的下一步之前完成,您会得到一些惊喜。例如:
3+2 %>% '*'(4) %>% `/`(2)
不做3+2=5, 5*4= 20, 20/2=10
而不是 2*4/2=4, 4+3=7
,因为 %>%
优先于 +
。
如果使用magrittr
包中的函数如:
add(3,2) %>% multiply_by(4) %>% divide_by(2)
您得到了预期的 10
。在 3+2
周围放置方括号也会得到 10
.
在我原来的例子中,逻辑运算符,例如 !
的优先级低于 %>%
,因此它们最后执行,在求和完成后。
故事的寓意:小心将 %>%
与其他运算符混合使用。
您还可以使用 magrittr 包中的 "not" 别名:
> is.na(1:20) %>% not %>% sum
[1] 20
我有 运行 遇到 %>%
与 !
结合时产生非常令人惊讶的输出的情况。考虑以下代码:
x <- c(1:20)
y <- !is.na(x)
> y
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
> sum(Y)
[1] 20
好的,没什么奇怪的。但是,如果我尝试使用 %>%
来缩短它,就会发生奇怪的事情:
!is.na(x) %>% sum
[1] TRUE
TRUE
??不是我所期望的 - 它应该是 20
。
如果我删除 !
,它会给我预期的 0
:
> is.na(x) %>% sum
[1] 0
如果我添加方括号,它会起作用:
> {!is.na(x)} %>% sum
[1] 20
并将 !
视为函数有效:
> is.na(x) %>% `!` %>% sum
[1] 20
!is.na(x) %>% sum
在做什么,为什么 return TRUE
而不是 20
?
编辑: 其他逻辑运算符产生类似的行为:
> T&T %>% sum()
[1] TRUE
> {T&T} %>% sum()
[1] 1
> T|T %>% sum()
[1] TRUE
> {T|T} %>% sum()
[1] 1
我怀疑是操作顺序问题:
!is.na(x) %>% sum
正在评估
!(is.na(x) %>% sum)
相当于TRUE
尽管我接受了@C-Z_ 的回答,但我想添加另一个来提供相关背景信息。感谢@rawr 指引我前往 ?Syntax
.
基本上 %>%
被认为是一个操作符,就像 %in%
一样,因此它必须遵守操作顺序。在 Syntax
帮助页面上,这对应于 %any%
运算符(即任何中缀运算符),因为用户可以随意定义它们。碰巧的是,这意味着 %>%
在任何逻辑运算符之前触发,也在算术运算符(例如 *
和 \
)之前触发。因此,如果您像我一样天真地认为 %>%
的左侧将在链中的下一步之前完成,您会得到一些惊喜。例如:
3+2 %>% '*'(4) %>% `/`(2)
不做3+2=5, 5*4= 20, 20/2=10
而不是 2*4/2=4, 4+3=7
,因为 %>%
优先于 +
。
如果使用magrittr
包中的函数如:
add(3,2) %>% multiply_by(4) %>% divide_by(2)
您得到了预期的 10
。在 3+2
周围放置方括号也会得到 10
.
在我原来的例子中,逻辑运算符,例如 !
的优先级低于 %>%
,因此它们最后执行,在求和完成后。
故事的寓意:小心将 %>%
与其他运算符混合使用。
您还可以使用 magrittr 包中的 "not" 别名:
> is.na(1:20) %>% not %>% sum
[1] 20