如何在purrr::map2()中结合dplyr的filter()与tidyselect选择器实现列表列数据过滤?
解决在
purrr::map2()中结合dplyr::filter()与tidyselect选择器的问题 问题根源
你碰到的错误核心是嵌套匿名函数的作用域冲突:在across()内部的~ . %in% .y里,.y已经不再指向map2()的第二个输入参数了——内层的~会创建一个独立的上下文环境,这个环境里没有定义.y,所以才会抛出"the ... list contains fewer than 2 elements"的错误。
两种可行解决方案
下面是最直接的两种修复方式,都能完美解决作用域的问题:
方案1:用命名函数替代~简写
把map2()的.f参数写成明确的命名函数,这样x和y的作用域会非常清晰,不会和内层的across()混淆:
library(tibble) library(dplyr) library(purrr) # 先重新构建示例数据 my_mtcars <- mtcars %>% rownames_to_column("cars") cars_to_keep <- c("Merc 240D", "Fiat X1-9", "Ferrari Dino") higher_level_tibble <- tibble(my_data = list(my_mtcars), the_cars_i_want = list(cars_to_keep)) # 修正后的代码 higher_level_tibble %>% mutate(my_filtered_data = map2( .x = my_data, .y = the_cars_i_want, .f = function(x, y) { filter(x, across(starts_with("cars"), ~ . %in% y)) } ))
方案2:用.env明确引用外层的.y
如果更习惯用~的简写方式,可以通过.env$.y明确指定要引用的是map2()上下文里的.y参数,避免内层环境的干扰:
higher_level_tibble %>% mutate(my_filtered_data = map2( .x = my_data, .y = the_cars_i_want, .f = ~ filter(.x, across(starts_with("cars"), ~ . %in% .env$.y)) ))
验证结果
两种方法都会输出你期望的结果:
## # A tibble: 1 x 3 ## my_data the_cars_i_want my_filtered_data ## <list> <list> <list> ## 1 <df [32 x 12]> <chr [3]> <df [3 x 12]>
展开my_filtered_data查看,里面就是你要保留的3条车型数据,和单独使用filter(across(...))的结果完全一致。
内容的提问来源于stack exchange,提问作者Emman
相关产品推荐
相关产品推荐

