如何组织大R功能?

时间:2011-08-31 08:43:32

标签: function r

我正在编写一个R函数,这个函数变得非常大。它允许多种选择,我正在组织它:

myfun <- function(y, type=c("aa", "bb", "cc", "dd" ... "zz")){

   if (type == "aa") {
      do something
      - a lot of code here -
      ....
   }

   if (type == "bb") {
      do something
      - a lot of code here -
      ....
   }

   ....
}

我有两个问题:

  1. 对于参数类型的每个选择,是否有更好的方法,以便不使用'if'语句?
  2. 为每个“类型”选择编写子函数是否更具功能性?
  3. 如果我写子功能,它看起来像这样:

    myfun <- function(y, type=c("aa", "bb", "cc", "dd" ... "zz")){
    
       if (type == "aa") result <- sub_fun_aa(y)
       if (type == "bb") result <- sub_fun_bb(y)
       if (type == "cc") result <- sub_fun_cc(y)
       if (type == "dd") result <- sub_fun_dd(y)
       ....
    }
    

    子功能当然在其他地方定义(在myfun的顶部,或以其他方式)。

    我希望我对自己的问题很清楚。在此先感谢。

    - 其他信息 -

    我正在编写一个函数,它将一些不同的滤镜应用于图像(不同的滤镜=不同的“类型”参数)。有些过滤器共享一些代码(例如,“aa”和“bb”是两个高斯过滤器,只有一个行代码不同),而其他过滤器完全不同。

    所以我被迫使用了很多if语句,即

     if(type == "aa" | type == "bb"){
      - do something common to aa and bb -
    
        if(type == "aa"){
          - do something aa-related -
        }
        if(type == "bb"){
          - do something bb-related -
        }
     }
    
     if(type == "cc" | type == "dd"){
      - do something common to cc and dd -
    
        if(type == "cc"){
          - do something cc-related -
        }
        if(type == "dd"){
          - do something dd-related -
        }
     }
    
    if(type == "zz"){
         - do something zz-related -
    }
    

    等等。 此外,代码中有一些if语句“做某事”。 我正在寻找组织代码的最佳方式。

4 个答案:

答案 0 :(得分:6)

选项1

一种选择是使用switch而不是多个if语句:

myfun <- function(y, type=c("aa", "bb", "cc", "dd" ... "zz")){
  switch(type, 
    "aa" = sub_fun_aa(y),
    "bb" = sub_fun_bb(y),
    "bb" = sub_fun_cc(y),
    "dd" = sub_fun_dd(y)
  )
}  

选项2

在您编辑的问题中,您提供了更具体的信息。以下是您可能需要考虑的一般设计模式。这种模式的关键因素是看不到一个if。我用match.function替换它,其中关键的想法是函数中的type本身就是一个函数(是的,因为R支持函数式编程,这是允许的)。:

sharpening <- function(x){
  paste(x, "General sharpening", sep=" - ")
}

unsharpMask <- function(x){
  y <- sharpening(x)
  #... Some specific stuff here...
  paste(y, "Unsharp mask", sep=" - ")
}

hiPass <- function(x) {
  y <- sharpening(x)
  #... Some specific stuff here...
  paste(y, "Hipass filter", sep=" - ")
}

generalMethod <- function(x, type=c(hiPass, unsharpMask, ...)){
  match.fun(type)(x)
}

并称之为:

> generalMethod("stuff", "unsharpMask")
[1] "stuff - General sharpening - Unsharp mask"
> hiPass("mystuff")
[1] "mystuff - General sharpening - Hipass filter"

答案 1 :(得分:5)

几乎没有理由不将代码重构为较小的函数。在这种情况下,除了重组之外,还有一个额外的好处:如果知道她在哪里,你的功能的受过教育的用户可以立即调用子功能。

如果这些函数有很多参数,解决方案(以便于维护)可以将它们分组到“myFunctionParameters”类列表中,但取决于您的情况。

如果代码在不同的sub_fun_xxs之间共享,只需将其插入到每个sub_fun_xxs中使用的另一个函数中,或者(如果可行的话)直接计算内容并将其直接传递给每个sub_fun_xx。

答案 2 :(得分:3)

这是一个关于程序设计的更普遍的问题。没有明确的答案,但几乎肯定会有比你现在做的更好的路线。

编写处理不同类型的函数是一条很好的路径。它的效果取决于几个方面 - 例如,有多少种不同的类型?它们是否完全相关,例如其中一些可以由同一个函数处理,根据输入的不同,行为会略有不同吗?

您应该尝试以模块化方式考虑代码。你有一个重要的任务要做。你能将它分解成一系列较小的任务,并编写执行较小任务的函数吗?你能否以一种不会使函数(更多)更难编写的方式来概括任何这些任务,但是它们是否能给它们更广泛的适用性?

如果您提供有关您的计划应该实现的更多细节,我们将能够为您提供更多帮助。

答案 3 :(得分:1)

这更像是一个普通的编程问题而不是R问题。因此,您可以遵循代码质量的基本准则。有些工具可以通过阅读代码生成代码质量报告,并为您提供有关如何改进的指导。一个这样的例子是Gendarme for .NET代码。以下是一个典型的指南,它会出现在一个包含太长方法的报告中:

AvoidLongMethodsRule