purrr::map_dfr() 的本地管道

Native pipe with purrr::map_dfr()

我想使用新的本地管道,|>, with purrr::map_dfr()。 (为了使其可重现,我将数据集作为字符串而不是路径传递,但这应该没有什么区别。)

csvs <- c(
  "csv_a" = "a,b,c\n1,2,3\n4,5,6",
  "csv_b" = "a,b,c\n-1,-2,-3"
)
col_types <- readr::cols(.default = readr::col_character())

# Approach 1
csvs |> 
  purrr::map_dfr(
    .f = function(p) {
      readr::read_csv(
        file = I(p),
        col_types = col_types
      )
    }
  )

# Approach 2
library(magrittr)
csvs %>%
  purrr::map_dfr(
    .x = .,
    .f = ~readr::read_csv(
      file      = I(.),
      col_types = col_types
    )
  )

我有两个问题,主要是

问题 1

如何用新的 {\(x)...}() 语法替换显式 function(p) 部分?下面的尝试抛出“standardise_path(file) 中的错误:缺少参数“p”,没有默认值”。

csvs |> 
  purrr::map_dfr(
    .f = 
      {\(p)
        readr::read_csv(
          file      = I(p),
          col_types = col_types
        )
      }()
  )

问题 2

我也可以模仿 magrittr 方法(#2)吗?这以某种方式读取每一行两次,包括 header.

csvs |> 
  {\(p)
    purrr::map_dfr(
      .x = p,
      .f = ~readr::read_csv(
        file      = I(p),
        col_types = col_types
      )
    )
  }()

# Produces
# A tibble: 8 x 3
  a     b     c    
  <chr> <chr> <chr>
1 1     2     3    
2 4     5     6    
3 a     b     c    
4 -1    -2    -3   
5 1     2     3    
6 4     5     6    
7 a     b     c    
8 -1    -2    -3   

edit:为了回应@MrFlick 的评论,我将 file 的论点与 I() 包装起来,以防将来成为要求readr 的版本(现在没有它似乎可以正常工作)。如果您要传递典型的文件路径(而不是文字字符串),请删除对 I().

的调用

问题 1 的答案 -

csvs |> 
  purrr::map_dfr(
    .f = \(k) {
      readr::read_csv(
        file      = k,
        col_types = col_types
      )
    }
  )

#     a     b     c
   <chr> <chr> <chr>
#1     1     2     3
#2     4     5     6
#3    -1    -2    -3

问题 2 的答案:对于内部函数,您使用 p,它在每次调用时重复使用 csvs。所以内部函数忽略了它映射的值,而是使用整个列表。您可以避免使用 .x 代词:

csvs |> 
  {\(p)
    purrr::map_dfr(
      .x = p,
      .f = ~readr::read_csv(
        file      = I(.x),
        col_types = col_types
      )
    )
  }()

从风格上讲,完全避免使用公式映射器可能更好,因为您的函数中没有任何自定义行为。 purrr::map_dfr 中的 ... 将在每次调用时传递给函数。1

csvs |> 
  {\(p) purrr::map_dfr(.x = p, .f = readr::read_csv, col_types = col_types)}()

因为你没有重复使用 p 参数,所以匿名函数也是不必要的:

csvs |> 
  purrr::map_dfr(.f = readr::read_csv, col_types = col_types)

1@MrFlick 是正确的,如果您希望使用字符串而不是文件名,原则上应该使用 I(),但是在您的情况下,您不需要它,因为 csvs 向量中的所有字符串中都有一个换行符。有关详细信息,请参阅 here。我把它拿出来说明你的选择。