如何计算 R 函数的圈复杂度?
环复杂度衡量通过一个函数可以采取多少个可能的分支。是否有现有的函数/工具来计算 R 函数?如果没有,欢迎提出编写最佳方式的建议。
一个简单的开始是计算函数中所有 if
、ifelse
或 switch
的出现次数。不过,要获得真正的答案,您需要了解分支何时开始和结束,这要困难得多。也许一些 R 解析工具可以帮助我们入门?
Cyclomatic complexity measures how many possible branches can be taken through a function. Is there an existing function/tool to calculate it for R functions? If not, suggestions are appreciated for the best way to write one.
A cheap start towards this would be to count up all the occurences of if
, ifelse
or switch
within your function. To get a real answer though, you need to understand when branches start and end, which is much harder. Maybe some R parsing tools would get us started?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用codetools::walkCode 来遍历代码树。不幸的是,codetools 的文档非常稀疏。以下是帮助您入门的解释和示例。
walkCode
接受一个表达式和一个代码遍历器。代码遍历器是您创建的一个列表,它必须包含三个回调函数:handler
、call
和leaf
。 (您可以使用辅助函数 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
的出现次数。希望这至少可以帮助您入门!You can use
codetools::walkCode
to walk the code tree. Unfortunately codetools' documentation is pretty sparse. Here's an explanation and sample to get you started.walkCode
takes an expression and a code walker. A code walker is a list that you create, that must contain three callback functions:handler
,call
, andleaf
. (You can use the helper functionmakeCodeWalker
to provide sensible default implementations of each.)walkCode
walks over the code tree and makes calls into the code walker as it goes.call(e, w)
is called when a compound expression is encountered.e
is the expression andw
is the code walker itself. The default implementation simply recurses into the expression's child nodes (for (ee in as.list(e)) if (!missing(ee)) walkCode(ee, w)
).leaf(e, w)
is called when a leaf node in the tree is encountered. Again,e
is the leaf node expression andw
is the code walker. The default implementation is simplyprint(e)
.handler(v, w)
is called for each compound expression and can be used to easily provide an alternative behavior tocall
for certain types of expressions.v
is the character string representation of the parent of the compound expression (a little hard to explain--but basically<-
if it's an assignment expression,{
if it's the start of a block,if
if it's an if-statement, etc.). If the handler returnsNULL
thencall
is invoked as usual; if you return a function instead, that's what's called instead of the function.Here's an extremely simplistic example that counts occurrences of
if
andifelse
of a function. Hopefully this can at least get you started!另外,我刚刚发现了一个名为 cyclocomp 的新软件包(2016 年发布)。一探究竟!
Also, I just found a new package called cyclocomp (released 2016). Check it out!