如何计算 R 函数的圈复杂度?

发布于 2024-11-29 04:34:21 字数 314 浏览 5 评论 0原文

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

一个简单的开始是计算函数中所有 ififelseswitch 的出现次数。不过,要获得真正的答案,您需要了解分支何时开始和结束,这要困难得多。也许一些 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

撕心裂肺的伤痛 2024-12-06 04:34:21

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

walkCode 接受一个表达式和一个代码遍历器。代码遍历器是您创建的一个列表,它必须包含三个回调函数:handlercallleaf。 (您可以使用辅助函数 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;如果你返回一个函数,那么这就是被调用的函数而不是函数。

这是一个极其简单的示例,用于计算函数中 ififelse 的出现次数。希望这至少可以帮助您入门!

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
}

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, and leaf. (You can use the helper function makeCodeWalker 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 and w 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 and w is the code walker. The default implementation is simply print(e).

handler(v, w) is called for each compound expression and can be used to easily provide an alternative behavior to call 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 returns NULL then call 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 and ifelse of a function. Hopefully this can at least get you started!

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
}
初见终念 2024-12-06 04:34:21

另外,我刚刚发现了一个名为 cyclocomp 的新软件包(2016 年发布)。一探究竟!

Also, I just found a new package called cyclocomp (released 2016). Check it out!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文