首页 > 解决方案 > Map conditionally over list of dataframes in R

问题描述

I have a list of similar dataframes--some have the correct column, some have the incorrect column, and some have both. I am have a lot of tables so am looking for a solution that loops through them without if statements or case_when. Maybe something using purrr::map_at or purrr::map_if??

Here's a simplified example, where I want to rename "rowid_2" to "rowid" for all dfs.

library(tidyverse)
mtcars1 <- mtcars %>% rowid_to_column(var = "rowid_2")
mtcars2 <- mtcars1 %>% mutate(rowid = rowid_2)
dfs <- list(mtcars1, mtcars2)
dfs %>% map(names)
#> [[1]]
#>  [1] "rowid_2" "mpg"     "cyl"     "disp"    "hp"      "drat"    "wt"     
#>  [8] "qsec"    "vs"      "am"      "gear"    "carb"   
#> 
#> [[2]]
#>  [1] "rowid_2" "mpg"     "cyl"     "disp"    "hp"      "drat"    "wt"     
#>  [8] "qsec"    "vs"      "am"      "gear"    "carb"    "rowid"

Here is my desired output:

list(
  mtcars1 %>% rename(rowid = rowid_2),
  mtcars2 # rowid_2 could also be deselected
) %>% map(names)
#> [[1]]
#>  [1] "rowid" "mpg"   "cyl"   "disp"  "hp"    "drat"  "wt"    "qsec"  "vs"   
#> [10] "am"    "gear"  "carb" 
#> 
#> [[2]]
#>  [1] "rowid_2" "mpg"     "cyl"     "disp"    "hp"      "drat"    "wt"     
#>  [8] "qsec"    "vs"      "am"      "gear"    "carb"    "rowid"

I tried this, but then I have two "rowid" columns in mtcars2.

dfs %>% map(~.x %>% rename_with(~"rowid", matches("rowid_2"))) %>% map(names)
#> Error: Names must be unique.
#> x These names are duplicated:
#>   * "rowid" at locations 1 and 13.

标签: rpurrr

解决方案


You can use map_if to only do the rename if rowid_2 exists in names(x) and rowid does not.

dfs %>% map_if(function(x) "rowid_2" %in% names(x) & !"rowid" %in% names(x), 
               function(x) rename(x, rowid = rowid_2)) %>% 
  map(names)

推荐阅读