如何无需$或索引,通过管道将函数输出传递为另一函数参数?
问题
我希望函数myFunction1的输出既能单独使用(它会执行计算并生成多类型结果值),也能通过管道%>%直接传递给myFunction2,自动为其设置全部或所需参数,预期代码形式如下:
myFunction1() %>% myFunction2()
目前我知道两种实现方式:
- 在
myFunction1中嵌套调用myFunction2,示例代码:
myFunction1=function(x, logical){ x=x^2 y="" if(x>100){ y="hello" }else{ y="goodbye" } if(logical){ return(list(x=x,y=y,logical=logical)) }else{ return(myFunction2(x,y,logical)) } } ##end myFunction1() myFunction2=function(x, y, z){ a=paste0(x, y, z) return(a) }
- 将
myFunction1的列表输出通过$运算符提取后传入myFunction2,示例代码:
myOutput = myFunction1(1, TRUE) myOutput2 = myFunction2(myOutput$x, myOutput$y, myOutput$logical)
我想知道:是否存在一种方法,无需使用$或索引,就能让列表(或其他支持多类型数据的结构)输出直接为另一个函数设置所有参数?
解决方案
当然有,R原生的do.call()函数就是专门解决这个需求的——它可以接收一个函数名,以及一个包含该函数所有参数的列表,自动把列表里的元素按名称(或位置)匹配到函数的参数上。
基础用法
首先需要确保myFunction1返回的列表元素名和myFunction2的参数名对应(比如把myFunction2的第三个参数名从z改成logical,和列表键名统一):
myFunction2=function(x, y, logical){ a=paste0(x, y, logical) return(a) }
之后直接用do.call传递列表即可:
myOutput = myFunction1(1, TRUE) do.call(myFunction2, myOutput)
结合管道的用法
要实现你想要的myFunction1() %>% myFunction2()形式,只需用匿名函数把do.call和管道结合:
myFunction1(1, TRUE) %>% {do.call(myFunction2, .)}
如果你常用tidyverse工具,也可以用purrr包的invoke()函数,它本身就支持管道传递列表参数:
library(purrr) myFunction1(1, TRUE) %>% invoke(myFunction2, .)
注意事项
- 优先保证列表元素名和函数参数名完全匹配,这种按名称匹配的方式比按位置匹配更稳妥,不易出错。
- 如果只需要传递部分参数,可以先从列表中筛选出对应元素,比如
myOutput[c("x", "y")]再传入函数。
内容的提问来源于stack exchange,提问作者scatter
相关产品推荐
相关产品推荐

