如何减少purrr::map中的参数冗余?
问题
map语句实用性很强,但输入经常存在不必要的冗余。比如下面的代码块里,必须重复列出已经从tibble中调用的变量,显得很繁琐。我希望能直接给匿名函数使用\()语法,有没有办法减少这种冗余?当然我可以用mutate完成下面的任务,这里只是用来演示需求。
library(tidyverse) mtcars |> as_tibble() |> mutate( test = pmap_chr( .l = list(mpg,cyl), .f = \(mpg,cyl){ # 太冗余了!!! str_glue("{mpg}_{cyl}") } ) )
PS:虽然~语法对我有帮助,但它已经不是最佳实践了。
PPS:这不算正式问题(涉及主观偏好),但你更倾向于在mutate里用map还是直接在列表上用map?我发现在mutate里用map更有条理,需要的准备工作也更少,但一直不确定这是不是好做法,我看到更多人是直接构建列表传入purrr::map。
解答
一、减少pmap匿名函数的冗余写法
有几种方法可以避免重复声明变量名,同时保留\()匿名函数的使用:
方法1:用...统一接收参数
直接用...指代所有传入的参数,配合str_glue_data自动解析参数名,不用重复写变量:
library(tidyverse) mtcars |> as_tibble() |> mutate( test = pmap_chr( .l = list(mpg, cyl), .f = \(...) str_glue_data(list(...), "{mpg}_{cyl}") ) )
方法2:用lift函数适配多参数场景
purrr::lift可以把普通多参数函数转换成接受列表的函数,刚好匹配pmap的输入逻辑:
mtcars |> as_tibble() |> mutate( test = pmap_chr( .l = list(mpg, cyl), .f = lift(str_glue, .n = 2) ) )
.n = 2指定参数数量,确保str_glue正确接收两个变量。
方法3:用rowwise替代map(更贴合tidy风格)
如果只是行内变量拼接这类简单操作,用rowwise配合c_across更简洁,完全不需要map:
mtcars |> as_tibble() |> rowwise() |> mutate(test = str_glue("{c_across(c(mpg, cyl))}") |> str_replace(", ", "_")) |> ungroup()
二、mutate中用map vs 直接在列表上用map的选择
没有绝对的优劣,完全看场景和工作流:
- mutate + map:适合和tidyverse的管道流结合,直接在数据框的处理链路中生成新列,无需额外构建列表,代码连贯性和可读性都很强,我个人在处理数据框内的行级计算时更常用这种方式,完全是合理的实践。
- 直接在列表上用map:适合独立的列表处理任务,比如处理非数据框的列表结构,或者需要对列表做复杂预处理后再映射的场景,灵活性更高。
核心原则是代码清晰易读,符合你的工作习惯——在数据框的tidy操作中,mutate+map的写法完全是实用且合理的选择。
内容的提问来源于stack exchange,提问作者Aegis
相关产品推荐
相关产品推荐

