17

圈复杂度衡量通过一个函数可以采用多少个可能的分支。是否有现有的函数/工具来计算 R 函数?如果没有,建议以最佳方式编写。

一个廉价的开始是计算所有出现的if,ifelseswitch在你的函数中。但是,要获得真正的答案,您需要了解分支何时开始和结束,这要困难得多。也许一些 R 解析工具会让我们开始?

4

2 回答 2

7

您可以使用codetools::walkCode遍历代码树。不幸的是,codetools 的文档非常稀少。这是一个解释和示例,可帮助您入门。

walkCode接受一个表达式和一个代码步行者。Code walker 是您创建的列表,它必须包含三个回调函数:handlercallleaf。(您可以使用 helper 函数makeCodeWalker为每个函数提供合理的默认实现。)walkCode遍历代码树并随时调用代码遍历器。

call(e, w)当遇到复合表达式时调用。e是表达式并且w是代码步行者本身。默认实现只是简单地递归到表达式的子节点 ( for (ee in as.list(e)) if (!missing(ee)) walkCode(ee, w))。

leaf(e, w)当遇到树中的叶节点时调用。同样,e是叶节点表达式并且w是代码步行者。默认实现是简单的print(e)

handler(v, w)为每个复合表达式调用,并且可用于轻松地call为某些类型的表达式提供替代行为。v是复合表达式的父级的字符串表示(有点难以解释——但基本上<-如果它是一个赋值表达式,{如果它是一个块的开始,if如果它是一个 if 语句等)。如果处理程序返回NULL,则call照常调用;如果你返回一个函数,那就是调用而不是函数。

这是一个极其简单的示例,它计算函数的出现次数if和次数。ifelse希望这至少可以让你开始!

library(codetools)

countBranches <- function(func) {
  count <- 0
  walkCode(body(func), 
           makeCodeWalker(
             handler=function(v, w) {
               if (v == 'if' || v == 'ifelse')
                 count <<- count + 1
               NULL  # allow normal recursion
             },
             leaf=function(e, w) NULL))
  count
}
于 2011-08-18T23:44:35.803 回答
4

另外,我刚刚发现了一个名为 cyclocomp 的新包(2016 年发布)。看看这个!

于 2016-05-24T22:03:00.830 回答