如何避免具有相似内容的长 if 链

How to avoid long if chain with similar content

我目前正在编写一个 R 函数 get_line_type(line) 来输出一行(字符串)的 type。对于每个当前可能的类型,都有一个 is_TYPENAME_line(line) 形式的函数,其中 returns 一个布尔值,指示该行是否属于此特定类型。将这些 is_TYPENAME_line 函数链接在一起创建 get_line_type(line) 函数,目前看起来像这样

is_fish_line <- function(line) {
  return (any(grep("fish", line)))
}

is_mouse_line <- function(line) {
  return (any(grep("mouse", line)))
}

get_line_type <- function(line) {
  identified_types <- character(0)

  if(is_fish_line(line)) { identified_types[length(identified_types) + 1] <- "FISH" }
  if(is_mouse_line(line)) { identified_types[length(identified_types) + 1] <- "MOUSE" }

  if (length(identified_types) > 1) {
    stop("Matched multiple types: ", paste(identified_types, collapse = ", "), "\t", "Line: ", line)
  }

  return(if(length(identified_types) == 1) identified_types[1] else "UNKOWN")
}

这段代码是这样工作的

> get_line_type("The fish seems happy.")
[1] "FISH"
> get_line_type("A mouse is living in this house.")
[1] "MOUSE"
> get_line_type("The tiger is the king of the jungle.")
[1] "UNKOWN"
> get_line_type("The fish and the mouse are friends.")
Error in get_line_type("The fish and the mouse are friends.") : 
  Matched multiple types: FISH, MOUSE Line: The fish and the mouse are friends.

在函数内部创建了一个列表 identified_types,其中包含参数行的所有已识别类型的名称。如果未找到类型,则返回 UNKOWN。如果恰好识别出一种类型,则返回识别出的类型。如果识别出不止一种类型,则会发生错误(这不应该发生)。

将来可能的类型列表可能会增加,我可以在链中添加另一个 if 语句来完成这项工作,但我想知道是否有更优雅的方法,因为每个条件看起来都很相似。

我不确定这是否是您要找的,但这里有一些事情需要考虑:

创建一个向量,其中包含您在函数中包含的 "TYPENAMES"。然后,您可以动态构建这些函数并将其放入名为 funcList.

的命名列表中

您的 get_line_type 函数可以调用所有函数并提供 line 作为参数。结果可以很容易地简化,因为你从这些函数中 return TRUEFALSE

我注意到您在评论中可能有两个词带有 space(例如,"product search")。在 all_types 中,您需要在这些词之间加上下划线以创建没有 space 的可用函数。此外,如果需要,可以修改 identified_types 以删除下划线。

all_types <- c("fish", "mouse")
funcList <- lapply(all_types, function(x) eval(parse(text = paste0('is_', x, '_line'))))
names(funcList) <- all_types

get_line_type <- function(line) {
  lst <- lapply(funcList, do.call, list(line))
  identified_types <- names(lst[unlist(lst)])
  if (length(identified_types) > 1) {
    stop("Matched multiple types: ", paste(identified_types, collapse = ", "), "\t", "Line: ", line)
  }
  return(if(length(identified_types) == 1) identified_types[1] else "UNKNOWN")
}