我是R的新手,目前我正在尝试为R函数(或RC/R6类方法)提供类似枚举的参数,我目前使用的是字符向量加上match.arg,如下所示:
EnumTest = function(enum = c("BLUE", "RED", "BLACK")) {
enumArg <-
switch(
match.arg(enum), "BLUE" = 0L, "RED" = 1L, "BLACK" = 2L
)
switch(enumArg,
# do something
)
}在R中有没有更好/更简洁的方法来模仿类似枚举的行为?例如,一个大问题是用户必须知道参数的可能值集,并手动将其键入为字符串-没有任何建议或自动完成……
如果没有其他更好的方法,有一件事可以改进上面的方法-通过全局预定义枚举或作为R6类的私有成员来使其更简洁:
Color <- c("BLUE", "RED", "BLACK")然后可以在一个或多个函数定义中(重新)使用它,例如:
EnumTest = function(enum = Color) {
...但是,我不确定如何在match.arg函数中使用这个Color向量。如果我可以将Color定义为一个映射,键是实际的颜色值,值是整数表示,那就太好了--但我不确定这是否合理。无论如何,也许还有更常见的整洁方法。
主要目标是为我的包和函数的用户提供一个易于使用的直观界面(例如,查找可能值集的简单方法、制表符完成、自动建议等),然后使用类似枚举的参数对这些函数进行标准化开发
发布于 2016-12-01 05:06:38
使用一个通过返回list(a= "a", ...)来定义枚举的函数怎么样?然后,您可以将返回的向量赋给一个变量并在上下文中使用它,或者直接使用该函数。名称或整数引用都可以用作索引,尽管您必须使用索引查找的非列表版本[[,否则会得到一个只有一个元素的列表。
colorEnum <- function() {
list(BLUE = "BLUE", RED = "RED", BLACK = "BLACK")
}
colorEnum()$BLUE
#> [1] "BLUE"
colorEnum()[[1]]
#> [1] "BLUE"
colorEnum()[1]
#> $BLUE
#> [1] "BLUE"
col <- colorEnum()
col$BLUE
#> [1] "BLUE"
col[[1]]
#> [1] "BLUE"
col$BAD_COLOR
#> NULL
col[[5]]
#> Error in col[[5]] : subscript out of bounds您可以获取在匹配中使用的名称列表,例如,您的函数参数可以是
EnumTest = function( enum = names(colorEnum()) { ...实际上你也可以缩写,但它必须是唯一的。(如果您使用RStudio,因为col是一个列表,它将建议完成!)
col$BLA
#> [1] "BLACK"
col$BL
#> NULL如果您想要更复杂的枚举处理,可以将S3类分配给您的枚举构造函数返回的内容,并编写一个小的函数集合来分派" enum“类,并允许不区分大小写的索引。您还可以添加特殊的函数来处理特定的类,例如"colorEnum";我在这里没有这样做。继承意味着列表访问方法仍然有效。
colorEnum2 <- function() {
structure(
list(BLUE = "BLUE", RED = "RED", BLACK = "BLACK"),
class= c("colorEnum2", "enum", "list")
)
}
# Note, changed example to allow multiple returned values.
`[.enum` <- function(x, i) {
if ( is.character( i ))
i <- toupper(i)
class(x) <- "list"
names(as.list(x)[i])
}
`[[.enum` <- function(x, i, exact= FALSE) {
if ( is.character( i ))
i <- toupper(i)
class(x) <- "list"
as.list(x)[[i, exact=exact]]
}
`$.enum` <- function(x, name) {
x[[name]]
}
col <- colorEnum2()
# All these return [1] "RED"
col$red
col$r
col[["red"]]
col[["r"]]
col["red"]
col[c("red", "BLUE")]
#> [1] "RED" "BLUE"
col["r"]
[1] NA # R does not matches partial strings with "["当被索引的对象属于“枚举”类时,这些函数会覆盖任何“枚举”类对象的内置[、[[和$函数。如果你需要另一个,你只需要定义它。
directionEnum <- function() {
structure(
list(LEFT = "LEFT", RIGHT = "RIGHT"),
class= c("directionEnum", "enum", "list")
)
}
directionEnum()$l
#> [1] "LEFT"如果需要几个枚举对象,可以添加一个工厂函数enum,该函数接受字符串向量和名称,并返回一个enum对象。这其中的大部分只是验证。
enum <- function(enums, name= NULL) {
if (length(enums) < 1)
stop ("Enums may not be empty." )
enums <- toupper(as.character(enums))
uniqueEnums <- unique(enums)
if ( ! identical( enums, uniqueEnums ))
stop ("Enums must be unique (ignoring case)." )
validNames <- make.names(enums)
if ( ! identical( enums, validNames ))
stop( "Enums must be valid R identifiers." )
enumClass <- c(name, "enum", "list")
obj <- as.list(enums)
names(obj) <- enums
structure( obj, class= enumClass)
}
col <- enum(c("BLUE", "red", "Black"), name = "TheColors")
col$R
#> [1] "RED"
class(col)
#> [1] "TheColors" "enum" "list"
side <- enum(c("left", "right"))
side$L
#> [1] "LEFT"
class(side)
#> [1] "enum" "list"但现在这开始看起来像是一个包裹。
发布于 2017-05-24 15:58:01
我喜欢使用环境作为枚举的替代,因为您可以锁定它们,以防止在创建后进行任何更改。我这样定义我的创建函数:
Enum <- function(...) {
## EDIT: use solution provided in comments to capture the arguments
values <- sapply(match.call(expand.dots = TRUE)[-1L], deparse)
stopifnot(identical(unique(values), values))
res <- setNames(seq_along(values), values)
res <- as.environment(as.list(res))
lockEnvironment(res, bindings = TRUE)
res
}创建一个新枚举,如下所示:
FRUITS <- Enum(APPLE, BANANA, MELON)我们可以访问这些值:
FRUITS$APPLE但我们不能修改它们或创建新的:
FRUITS$APPLE <- 99 # gives error
FRUITS$NEW <- 88 # gives error发布于 2016-11-02 20:48:15
我刚刚面对了这个问题,只能找到这个问题。Paul提到的objectProperties包似乎被抛弃了(它产生了几个警告),对于这样一个简单的(原则上)问题,它有很多开销。我想出了以下轻量级解决方案(仅依赖于stringi包),它在C语言中重现了枚举的感觉。也许这对某些人有帮助。
EnumTest <- function(colorEnum = ColorEnum$BLUE) {
enumArg <- as.character(match.call()[2])
match.arg(enumArg, stringi::stri_c("ColorEnum$", names(ColorEnum)))
sprintf("%s: %i",enumArg,colorEnum)
}
ColorEnum <- list(BLUE = 0L, RED = 1L, BLACK = 2L)https://stackoverflow.com/questions/33838392
复制相似问题