R 中是否有类似于 Rust 模式语法的东西?

问题描述

我知道 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)。