如何覆盖magrittr管道操作符?

时间:2017-07-21 11:11:15

标签: r dplyr magrittr

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

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

我在每个这样的步骤之后用nrow检查数据集的当前状态,所以我认为我可以按照

的行覆盖管道%<>%运算符
`%<?>%` <- 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内部结构?

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

3 个答案:

答案 0 :(得分:3)

您可以使用TaskCallback,只要顶级任务完成就会执行。在回调检查中,表达式是否包含%<>%运算符,如果是,则打印结果:

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

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

addTaskCallback(printAssignmentPipe)

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

答案 1 :(得分:1)

由于链条利用了懒惰的评估,更好的翻译会是这样的:

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

我们基本上重写函数调用并对其进行评估。

答案 2 :(得分:1)

请注意,您可以通过这种方式进行开/关切换,而不是使用%<?>%代替%<>%

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