【问题标题】:Can an R function behaiviour change depending of number of arguments received?R 函数的行为可以根据接收到的参数数量而改变吗?
【发布时间】:2019-08-19 00:57:10
【问题描述】:

到目前为止,我已经创建了一个函数,该函数可以根据接收数字或字符作为输入来改变其行为,一个最小的示例可能如下:

...

f <- function(x)
  UseMethod("g")

f.numeric <- function(x)
  return(x^2)

f.character <- function(x)
  return("Hey, dude. WTF are you doing? Don't give me characters!")

...

现在假设我希望 f 能够接收两个数字作为输入并返回其总和,而不会丢失之前的功能。我怎样才能做到这一点?。

【问题讨论】:

标签: r function class arguments polymorphism


【解决方案1】:

可以重写函数来自己进行检查吗?比如……

f <- function(x, y=NA){
  if (all(is.numeric(c(x,y))) & !is.na(y)){
    return(x+y)
  }else if(is.numeric(x)){
    return(x^2)
  }else if(is.character(x)){
    return("Hey, dude. WTF are you doing? Don't give me characters!")
  }else{
    return("Hey, dude. I don't know what you are giving me?!")
  }
}

【讨论】:

  • 这是可能的,但是我必须检查的条件数量很大,我的代码看起来有点乱
【解决方案2】:

使用省略号很容易实现:

f <- function(x,...)
{
  if(missing(...))
  {
    if(is.numeric(x)) return(x^2)
    if(is.character(x)) return("Hey, dude. WTF are you doing? Don't give me characters!")
  }else
  {
    if(any(is.character(c(x,...)))  return("Hey, dude. WTF are you doing? Don't give me characters!"))
    return(x+..1)
  }
}

> f("foo")
[1] "Hey, dude. WTF are you doing? Don't give me characters!"
> f(4)
[1] 16
> f(4,5)
[1] 9

【讨论】:

  • 我认为最终的解决方案会和这个类似,根据missing(...)是TRUE还是FALSE调用一组不同的方法
  • 这行得通。在这种情况下省略号非常好,因为您可以在以后轻松添加更多参数。因此,如果您想要一个可以接受 3 个参数的函数,您只需将它们分别引用为 ..1..2。可以随意扩展。
【解决方案3】:

不确定这是否是您需要的,但也许它会有所帮助:)

sum_them <- function(var1, var2, na.rm = F)
{
  if(all(is.numeric(c(var1, var2)))) return(sum(c(var1, var2), na.rm = na.rm))
  return("non numeric argument")

}

sum_them("test", "this")
sum_them("test", 10)
sum_them(5, "this")
sum_them(5, 10)
sum_them(NA, 10)
sum_them(NA, 10, na.rm = T)

输出

> sum_them("test", "this")
[1] "non numeric argument"
> sum_them("test", 10)
[1] "non numeric argument"
> sum_them(5, "this")
[1] "non numeric argument"
> sum_them(5, 10)
[1] 15
> sum_them(NA, 10)
[1] NA
> sum_them(NA, 10, na.rm = T)
[1] 10

更新的功能,因为如果它只是 1 个数字,我没有得到不同的东西。

背后的逻辑: 如果只有 1 个参数 (var1),可以随心所欲地使用它,但如果它不是数字,请尝试捕获。 如果所有参数都是数字,则将它们相加。 否则返回一些字符串。

   sum_them <- function(var1, ..., na.rm = F)
{
  if(missing(...)) tryCatch({var1 <- var1^2}, warning = function(w){}, error = function(e){})
  if(all(is.numeric(c(var1, ...)))) return(sum(c(var1, ...), na.rm = na.rm))
  return("non numeric argument")

}

新输出:

> sum_them("test", "this")
[1] "non numeric argument"
> sum_them("test", 10)
[1] "non numeric argument"
> sum_them(5, "this")
[1] "non numeric argument"
> sum_them(5, 10)
[1] 15
> sum_them(NA, 10)
[1] NA
> sum_them(NA, 10, na.rm = T)
[1] 10
> sum_them(NA, na.rm = T)
[1] 0
> sum_them(10, na.rm = T)
[1] 100
> sum_them(10)
[1] 100
> sum_them("test")
[1] "non numeric argument"
> sum_them(10,10,10,10, NA)
[1] NA
> sum_them(10,10,10,10, NA, na.rm = T)
[1] 40
> sum_them(10,10,10,test, NA, na.rm = T)
[1] "non numeric argument"

【讨论】:

    【解决方案4】:

    如果您正在寻找类似 C 的方法签名[1] 的东西,那么不,我不知道 R 有任何这种性质的东西。

    我在 R 中所知道的最接近的是,您有一个“超级函数”,它接受所有参数,然后是一组子函数,超级函数分配给这些子函数。例如,考虑(我在下面概述的内容与 Julian_Hn 的答案在功能上没有什么不同。使用省略号和显式命名参数之间的区别在于对用户可以传递给函数的内容的控制量。如果您使用省略号,您对参数是否存在的测试看起来会有所不同)

    super_function <- function(x = NULL, y = NULL){
      if (!is.null(x) & is.null(y)){
        if (is.character(x)){
          sub_function_xchar(x)
        } else if {
          (is.numeric(x)){
            sub_function_xnum(x)
          }
        } else {
          sub_function_xelse(x)
        }
      } else {
        if (!is.null(x) & !is.null(y)){
          if (is.character(x) & is.character(y)){
            sub_function_xychar(x, y)
          } else {
            # Okay, I think you might get the point now
          }
        }
      }
    }
    
    sub_function_xchar <- function(x){
      # whatever you want to do with x as a character
    }
    
    sub_function_xnum <- function(x){
      # whatever you want to do with x as a numeric
    }
    
    sub_function_xelse <- function(x){
      # whatever you want to do with any other class of x
    }
    
    sub_function_xychar <- function(x, y){
      # whatever you want to do with x and y as characters
    }
    

    是的,很乱。我已经成功地使用了这样的方法来处理少量参数。我不知道我会推荐它用于大量参数。相反,如果你有很多争论,我建议你想办法把你打算做的任何任务分解成更小的块,每个块都可以隔离到它们自己的函数中。

    [1] 不确定我是否理解了这个术语,但 C 中许多方法可能具有相同名称的功能,但它们在它们接受的参数的集合和类型上必须是唯一的。

    【讨论】:

    • 您的函数可以通过在所有非空参数数量为常数的部分中使用 UseMethod() 来简化
    • UseMethod 不是一次只允许你指向一个对象的方法吗?如果我有 xcharacterx,但希望根据后续对象的类改变行为,我不确定如何利用它来发挥我的优势?除了处理方法中的所有逻辑之外,这似乎同样愚蠢。但我愿意接受教导。
    【解决方案5】:

    如果您想继续使用 S3,您可以使用 ...length() (>= R 3.4.2):

    f <- function(...)
      UseMethod("f")
    
    f.numeric <- function(...)
      if(...length() == 1) ..1^2 else sum(...) 
    
    f.character <- function(...)
      return("Hey, dude. WTF are you doing? Don't give me characters!")
    
    f(2)
    #[1] 4
    
    f(3,4)
    # [1] 7
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-14
      • 2023-03-17
      • 1970-01-01
      • 2018-04-30
      • 1970-01-01
      • 2018-10-02
      相关资源
      最近更新 更多