问题描述
我知道 R 中的 switch 语句,但我很好奇是否有一种方法可以将相同的动作/值分配给同一臂中的多个模式,类似于 Rust 中的方式:
let x = 1;
match x {
1 | 2 => println!("one or two"),3 => println!("three"),_ => println!("anything"),}
我不需要为 1 和 2 编写两个单独的案例,我可以用“|”将它们合二为一。如果之前没有匹配的模式,如果我可以定义默认情况(“_”)也会很有帮助。
解决方法
没有赋值的前面的值会继续,直到找到指定的值。
switch(
as.character(x),"1"=,"2"="one or two","3"="three","anything"
)
我使用 as.character(x)
而不是 x
因为 EXPR
(第一个参数)可能被解释为位置而不是相等。来自?switch
:
If the value of 'EXPR' is not a character string it is coerced to
integer. Note that this also happens for 'factor's,with a
warning,as typically the character level is meant. If the
integer is between 1 and 'nargs()-1' then the corresponding
element of '...' is evaluated and the result returned: thus if the
first argument is '3' then the fourth argument is evaluated and
returned.
所以如果 x
是一个介于 1 和其他参数数量之间的整数,那么它被解释为位置指示符,如
switch(3,'a','z','y','f')
# [1] "y"
这意味着命名参数被有效地忽略,就像这个非常令人困惑的例子
switch(3,'1'='a','3'='z','2'='y','4'='f')
# [1] "y"
请注意,帮助未引用大于 nargs()-1
的非字符串...这些整数返回 null:
(switch(9,'4'='f'))
# NULL
由于它是您要匹配的整数的值,因此您需要混淆地转换为字符串:
switch(as.character(3),'4'='f')
# [1] "z"
或者,
dplyr::case_when(
x %in% 1:2 ~ "one or two",x == 3 ~ "three",TRUE ~ "anything"
)
# [1] "one or two"
或
data.table::fcase(
x %in% 1:2,"one or two",x == 3,"three",rep(TRUE,length(x)),"anything"
)
(需要 rep(TRUE,length(x))
是因为 fcase
要求所有参数的长度完全相同,即它不允许像许多 R 函数允许的那样回收。我个人更喜欢它们允许 {{ 1}} 回收而不是 1 or N
,但目前不是这样。)
这有一个优点,它是自然矢量化的。
only N
仅对长度为 1 友好。向量 switch
的解决方法可能是
x
(或者,更好的是,sapply(x,switch,'4'='f')
强制返回 vapply
)。