[英]Using dplyr::if_else with purrr
I am trying to use purrr::map_dbl
on a list where I want different behavior if the list element is NULL
. 我正在尝试在列表上使用
purrr::map_dbl
,如果列表元素为NULL
,我希望该行为不同。
x <- list(NULL, c(1, 2), c(3, 4))
purrr::map_dbl(x, function(y) { dplyr::if_else(is.null(y), 0, y[1] + y[2]) })
This does not work as expected, instead giving the error: 这不能按预期方式工作,而是出现错误:
Error:
false
must be length 1 (length ofcondition
), not 0错误:
false
必须为长度1(condition
长度),而不是0
Debugging the if_else
call, I see that y[1] + y[2]
is evaluated to integer(0)
. 调试
if_else
调用后,我看到y[1] + y[2]
为integer(0)
。 Why doesn't this work? 为什么不起作用?
The following all work as I would expect: 我期望以下所有工作:
> purrr::map_dbl(x, function(y) { dplyr::if_else(is.null(y), 0, y[1]) })
[1] 0 1 3
> purrr::map_dbl(x, function(y) { dplyr::if_else(is.null(y), 0, y[2]) })
[1] 0 2 4
> purrr::map_dbl(x, ~ dplyr::if_else(is.null(.x), 0, .x[1]))
[1] 0 1 3
> purrr::map_dbl(x, function(y) { base::ifelse(is.null(y), 0, y[1] + y[2]) })
[1] 0 3 7
> purrr::map_dbl(x, function(y) { if (is.null(y)) 0 else y[1] + y[2] })
[1] 0 3 7
What is different about the original call? 原始通话有何不同?
An alternative is to use the na.rm
argument in sum
to ignore NA
or NULL
values when adding values together. 另一种选择是在将值加在一起时,使用
sum
的na.rm
参数忽略NA
或NULL
值。 This way we can skip the if else logic: 这样,我们可以跳过if else逻辑:
purrr::map_dbl(x, sum, na.rm = TRUE)
# [1] 0 3 7
Here is the Base R equivalent (as pointed out by akrun): 这是Base R的等效项(如akrun所指出):
sapply(x, sum, na.rm = TRUE)
We can debug, it easily with browser()
我们可以使用
browser()
轻松调试
purrr::map_dbl(x, function(y) {
browser()
dplyr::if_else(is.null(y), 0, y[1] + y[2])
})
Called from: .f(.x[[i]], ...)
Browse[1]>
debug at #1: dplyr::if_else(is.null(y), 0, y[1] + y[2])
Browse[2]>
Error: `false` must be length 1 (length of `condition`), not 0
Call `rlang::last_error()` to see a backtrace
So, here the length
is the issue. 因此,这里的
length
就是问题。
According to ?if_else
, requires all arguments to have the same length 根据
?if_else
,要求所有参数具有相同的长度
Values to use for TRUE and FALSE values of condition.
用于条件的TRUE和FALSE值的值。 They must be either the same length as condition, or length 1. They must also be the same type: if_else() checks that they have the same type and same class.
它们的长度必须与条件相同,或者长度为1。它们还必须具有相同的类型:if_else()检查它们是否具有相同的类型和相同的类。 All other attributes are taken from true.
所有其他属性均取自true。
To dig further into the issue, it still works if the value is not NULL
要进一步研究问题,如果该值不为
NULL
,它仍然可以使用
v1 <- 1
if_else(v1==1, 0, v1[1] + v1[2])
#[1] 0
But, as soon as we change it to NA
or NULL
, it becomes an issue, could be due to the type
但是,一旦我们将其更改为
NA
或NULL
,它就成为问题,可能是由于type
@CBraun made an interesting observation @CBraun做了一个有趣的观察
NULL[1] + NULL[2]
#integer(0)
returns length 0, 返回长度为0,
if_else(is.na(v1), 0, integer(0))
Error:
false
must be length 1 (length ofcondition
), not 0 Callrlang::last_error()
to see a backtrace错误:
false
长度必须为1(condition
长度),而不是0调用rlang::last_error()
以查看回溯
However, 然而,
NA + NA #[1] NA NA + NA#[1] NA
is of length
1, but still returns error 的
length
1,但仍返回错误
v1 <- NA
if_else(is.na(v1), 0, v1[1] + v1[2])
Error:
false
must be a double vector, not an integer vector Callrlang::last_error()
to see a backtrace错误:
false
必须是双rlang::last_error()
向量,而不是整数向量调用rlang::last_error()
以查看回溯
If we use the correct NA
dispatched, it works 如果我们使用正确的
NA
,则可以使用
v1 <- NA_real_
if_else(is.na(v1), 0, v1[1] + v1[2])
#[1] 0
Notice that here it is the type
issue. 请注意,这是
type
问题。 All in all, as mentioned in the documentation, length
and type
should match for if_else
总而言之,如文档中所述,
length
和type
应与if_else
匹配
Bottomline: When the value is NULL
, the behavior is strange because of the output of +
is integer(0)
of length 0 底线:当值为
NULL
,行为是奇怪的,因为+
的输出是长度为0的integer(0)
It is a case where we can use if/else
instead of if_else
在这种情况下,我们可以使用
if/else
代替if_else
purrr::map_dbl(x, ~ if(is.null(.x)) 0 else sum(.x))
#[1] 0 3 7
In that respect, use the sum
instead of calling the arguments separately y[[1]]
, y[[2]]
as this cause imbalance in the length 在这方面,请使用
sum
而不要分别调用y[[1]]
和y[[2]]
因为这会导致长度不平衡
purrr::map_dbl(x, ~ ifelse(is.null(.x), 0, sum(.x)))
#[1] 0 3 7
Note that ifelse
also requires the lengths to be same, though it works here due to recycling of values 请注意,
ifelse
也要求长度相同,尽管由于值的循环在这里起作用
A vector of the same length and attributes (including dimensions and "class") as test and data values from the values of yes or no.
一个矢量,其长度和属性(包括尺寸和“类别”)与来自“是”或“否”值的测试值和数据值相同。
purrr::map_dbl(x, ~ ifelse(is.null(.x), 0, .x[[1]] + .x[[2]]))
#[1] 0 3 7
NOTE: All the methods are used to check the OP's condition. 注意:所有方法均用于检查OP的状况。 But, if the objective is to get the result, there are other ways.
但是,如果目标是获得结果,则还有其他方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.