管道是使用单个命令链时使代码更具可读性的好方法
然而,在某些情况下,我觉得有人不得不通过创建不必要的临时变量,混合管道和嵌入式括号或定义自定义函数来与其哲学不一致。
例如,请参阅此SO问题,其中OP想知道如何使用管道将colnames转换为小写:Dplyr or Magrittr - tolower?
我会忘记names<-
的存在来说明我的观点
基本上有3种方法可以做到:
使用临时变量
temp <- df %>% names %>% tolower
df %>% setNames(temp)
使用嵌入式括号
df %>% setNames(tolower(names(.)))
定义自定义功能
upcase <- function(df) {names(df) <- tolower(names(df)); df}
df %>% upcase
我认为能够做到这样的事情会更加一致:
df %T>% # create new branch with %T%>%
{names(.) %>% tolower %as% n} %>% # parallel branch assigned to alias n, then going back to main branch with %>%
setNames(n) # combine branches
对于更复杂的情况,我认为它比上面的3个例子更具可读性,而且我没有污染我的工作区。
到目前为止,我已经能够非常接近,我可以输入:
df %T>%
{names(.) %>% tolower %as% n} %>%
setNames(A(n));fp()
或(对旧学校计算器有点致敬)
df %1% # puts lhs in first memory slot (notice "%1%", I define these up to "%9%")
names %>%
tolower %>%
setNames(M(1),.);fp() # call the first stored value
(见底部代码)
我的问题如下:
fp()
手动刷新它,这很难看A
函数,但我不太了解管道链的环境结构这样做这是我的代码:
PipeAliasEnv
的环境
%as%
在隔离环境中创建别名%to%
在调用环境中创建变量A
调用别名fp
从PipeAliasEnv
这是我使用的代码,可重复的示例以4种不同的方式解决:
library(magrittr)
alias_init <- function(){
assign("PipeAliasEnv",new.env(),envir=.GlobalEnv)
assign("%as%" ,function(value,variable) {assign(as.character(substitute(variable)),value,envir=PipeAliasEnv)},envir=.GlobalEnv)
assign("%to%" ,function(value,variable) {assign(as.character(substitute(variable)),value,envir=parent.frame())},envir=.GlobalEnv)
assign("A" ,function(variable) { get(as.character(substitute(variable)), envir=PipeAliasEnv)},envir=.GlobalEnv)
assign("fp" ,function(remove_envir=FALSE){if(remove_envir) rm(PipeAliasEnv,envir=.GlobalEnv) else rm(list=ls(envir=PipeAliasEnv),envir=PipeAliasEnv)},envir=.GlobalEnv) # flush environment
# to handle `%i%` and M(i) notation, 9 should be enough :
sapply(1:9,function(i){assign(paste0("%",i,"%"),eval(parse(text=paste0('function(lhs,rhs){lhs <- eval(lhs)
rhs <- as.character(substitute(rhs))
str <- paste("lhs %>%",rhs[1],"(",paste(rhs[-1],collapse=","),")")
assign("x',i,'",lhs,envir=PipeAliasEnv)
eval(parse(text= str))}'))),envir=.GlobalEnv)})
assign("M" ,function(i) { get(paste0("x",as.character(substitute(i))), envir=PipeAliasEnv)},envir=.GlobalEnv)
}
alias_init()
# using %as%
df <- iris %T>%
{names(.) %>% toupper %as% n} %>%
setNames(A(n)) %T>%
{. %>% head %>% print}(.) ;fp()
# still using %as%, choosing another main chain
df <- iris %as% dataset %>%
names %>%
toupper %>%
setNames(A(dataset),.) %T>%
{. %>% head %>% print}(.);fp()
# using %to% (notice no assignment on 1st line)
iris %T>%
{names(.) %>% toupper %as% n} %>%
{setNames(.,A(n))} %to% df %>% # no need for '%T>%' and '{}' here
head %>% print;fp()
# or using the old school calculator fashion (probably the clearest for this precise task)
df <- iris %1%
names %>%
toupper %>%
setNames(M(1),.) %T>%
{. %>% head %>% print}(.);fp()
我的问题简短:
如何摆脱A
和fp
?
奖励:%to%
在{}
内无法使用,我该如何解决?