【问题标题】:How to override magrittr pipe operator?如何覆盖 magrittr 管道运算符?
【发布时间】:2017-07-21 11:11:15
【问题描述】:

假设我有一个数据集,我想使用管道语法对其应用多个过滤器,如下所示:

library(magrittr)
library(dplyr)
mtcars %<>% 
  filter(cyl == 4) %>% 
  select(cyl, mpg)
nrow(mtcars)
#[1] 11

我在每个这样的步骤之后用nrow检查数据集的当前状态,所以我想我可以覆盖管道%&lt;&gt;%操作符

`%<?>%` <- function(lhs, rhs) {
  x <- magrittr::`%<>%`(lhs, rhs)
  if (is.data.frame(x) & pipeVerbose) print(nrow(x))
}
#Using this will generate errors like
#Error in pipes[[i]] : subscript out of bounds

现在通过打开或关闭pipeVerbose 标志,我将控制整个流程的跟踪过程。显然不是那么简单,因为内部评估机制,提示here。问题是,是否有可能以最小的努力实现所需的行为,即不修补 magittr 内部?

我不得不承认整个想法有点令人不安,但我的实际情况有点复杂,我想通过一个简单的开/关开关隐藏一些调试/开发细节以进行演示。

【问题讨论】:

  • 如果我理解得很好,您想在管道的每个步骤上打印 nrow 的输出吗?
  • @ColinFAY 不完全;仅当使用 %&lt;&gt;% 重新分配时,并且没有在任何地方附加额外的管道步骤,例如 %&gt;% nrow
  • 可能相关:rmonad

标签: r dplyr magrittr


【解决方案1】:

您可以使用TaskCallback,它在顶级任务完成时执行。在回调中检查表达式是否包含%&lt;&gt;% 运算符,如果是则打印结果:

printAssignmentPipe <- function(exp, res, success, printed){

  if (any(grepl("%<>%", exp, fixed = T))) {
    print(res)
  }
  TRUE
}

addTaskCallback(printAssignmentPipe)

您可以轻松扩展回调以检查pipeVerbose 的值,或者您只需调用addTaskCallbackremoveTaskCallback 来激活/停用。

【讨论】:

    【解决方案2】:

    由于链利用惰性求值,更好的翻译应该是这样的:

    `%<?>%` <- function(lhs, rhs) {
      call <- match.call()
      call[[1]] <- quote(`%<>%`)
      x <- eval.parent(call)
      if (is.data.frame(x) & pipeVerbose) print(nrow(x))
    }
    

    我们基本上是重写函数调用并评估它。

    【讨论】:

      【解决方案3】:

      请注意,您可以通过这种方式打开/关闭开关,不会比使用 %&lt;?&gt;% 而不是 %&lt;&gt;% 更明显:

      p <- function(x){if(pipeVerbose) print(nrow(x))}
      
      pipeVerbose <- FALSE
      mtcars %<>% 
        filter(cyl == 4) %>% 
        select(cyl, mpg) %T>% p
      
      rm(mtcars)
      pipeVerbose <- TRUE
      mtcars %<>% 
        filter(cyl == 4) %>% 
        select(cyl, mpg) %T>% p
      

      【讨论】:

      • 谢谢;这与我最终得出的结论非常接近。
      猜你喜欢
      • 1970-01-01
      • 2015-03-12
      • 2014-01-05
      • 2011-04-12
      • 1970-01-01
      • 2023-01-13
      相关资源
      最近更新 更多