具有 ifelse 行为的 magrittr 管道 (%>%) 的原因?
Reason for magrittr pipe (%>%) with ifelse behavior?
在条件和 ifelse 分支中都使用转发结果的情况下,我将 ifelse 与管道一起使用。下面是一个简化版本:ifelse + pipe 似乎只处理与 .
不同的条件,如果放在花括号内。
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"
我最初的目标:
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] ""
使用 {}
对我来说已经足够了,但我想了解这种行为的原因。
编辑:
尽管 问题讨论了一个相关主题并且我最初看到将 ifelse 放在花括号内的想法但是在表达式/函数调用中简单地使用 .
或使用 .
之间没有区别是我问题的重点。
magrittr
文档说,当在嵌套函数调用中使用点时,它的行为与您看到的一样。
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 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))
.
所以推荐的解决方案实际上是使用您已经找到的花括号。
逻辑评估似乎是 ifelse
中的一个单独的函数调用,因此也是它如此表现的原因。
我认为错误信息很清楚。
当你使用{}
时,{}
中的.
被替换到%>%
的左边。
当你调用一个没有{}
的函数时,第一个参数是lhs,而你显式编码的其他参数将向右移动,此外(see here) :
LHS is needed at a position other than the first, one can use the
dot,'.', as placeholder.
因此,FALSE %>% ifelse(. == TRUE, 'true', 'false')
实际上调用的是:
ifelse(FALSE, FALSE == TRUE, 'true', 'false')
和FALSE %>% {ifelse(. == TRUE, 'true', 'false')}
实际上是调用:
ifelse(FALSE == TRUE, 'true', 'false')
也许这对您的情况更令人满意:
NULL %>% as.character %>% inset(length(.)==0, value ="")
在条件和 ifelse 分支中都使用转发结果的情况下,我将 ifelse 与管道一起使用。下面是一个简化版本:ifelse + pipe 似乎只处理与 .
不同的条件,如果放在花括号内。
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"
我最初的目标:
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] ""
使用 {}
对我来说已经足够了,但我想了解这种行为的原因。
编辑:
尽管 .
或使用 .
之间没有区别是我问题的重点。
magrittr
文档说,当在嵌套函数调用中使用点时,它的行为与您看到的一样。
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))
.
所以推荐的解决方案实际上是使用您已经找到的花括号。
逻辑评估似乎是 ifelse
中的一个单独的函数调用,因此也是它如此表现的原因。
我认为错误信息很清楚。
当你使用
{}
时,{}
中的.
被替换到%>%
的左边。当你调用一个没有
{}
的函数时,第一个参数是lhs,而你显式编码的其他参数将向右移动,此外(see here) :
LHS is needed at a position other than the first, one can use the dot,'.', as placeholder.
因此,FALSE %>% ifelse(. == TRUE, 'true', 'false')
实际上调用的是:
ifelse(FALSE, FALSE == TRUE, 'true', 'false')
和FALSE %>% {ifelse(. == TRUE, 'true', 'false')}
实际上是调用:
ifelse(FALSE == TRUE, 'true', 'false')
也许这对您的情况更令人满意:
NULL %>% as.character %>% inset(length(.)==0, value ="")