【问题标题】:using `purrr::map` with compose functions使用 `purrr::map` 和 compose 函数
【发布时间】:2019-12-20 04:12:06
【问题描述】:

我想知道如何使用purrr::map,其中.f 是两个不同函数的组合。

首先,让我们创建一个用于映射复合函数的列表:

library(tidyverse)

# create a list
x <- list(mtcars, tibble::as_tibble(iris), c("x", "y", "z"))

# extracting class of objects
purrr::map(.x = x, .f = class)
#> [[1]]
#> [1] "data.frame"
#> 
#> [[2]]
#> [1] "tbl_df"     "tbl"        "data.frame"
#> 
#> [[3]]
#> [1] "character"

现在假设我要提取列表中每个元素的class第一个元素:

# this works but uses `map` twice
purrr::map(.x = x, .f = class) %>%
  purrr::map(.x = ., .f = `[[`, i = 1L)

#> [[1]]
#> [1] "data.frame"
#> 
#> [[2]]
#> [1] "tbl_df"
#> 
#> [[3]]
#> [1] "character"

这行得通,但我想避免使用map 两次,并且想编写一个可以一步提取类及其第一个元素的函数。所以我尝试编写这样一个函数,但它不能很好地与map

# error

purrr::map(.x = x, .f = purrr::compose(class, `[[`, i = 1L))
#> Can't convert an integer vector to function

# no error but not the expected output

purrr::map(.x = x, .f = purrr::compose(class, `[[`), i = 1L)
#> [[1]]
#> [1] "numeric"
#> 
#> [[2]]
#> [1] "numeric"
#> 
#> [[3]]
#> [1] "character"

我该怎么做?

【问题讨论】:

  • 不会map(x, ~ first(class(.x))) 工作
  • 或使用 compose:purrr::map(x, purrr::compose(first, class))purrr::map(x, purrr::compose(~.[[1]], class))。您不能真正从组合外部将不同的参数传递给组合中函数的不同部分。
  • @akrun 成功了!如果我一心想要使用[[purrr::map(x, ~class(.x)[[1]]) 也可以。你能发布你的答案,我会接受。

标签: r functional-programming tidyverse purrr


【解决方案1】:

如果我们使用~,只需包装first 即可获得预期的输出

library(purrr)
map(x, ~ first(class(.)))

【讨论】:

  • .x 不需要x
  • @RuiBarradas。抱歉,没有收到您的评论。这里的“x”是list 对象
  • map(x, ~ first(class(.))) 给了我与map(x, ~ first(class(.x))) 相同的输出
  • @RuiBarradas。是的,这是真的,在?map 中显示For a single argument function, use . 它可以是..x。当map2 中有两个参数时,.x 变得相关。我不想更改mapmap2 中的参数,所以使用了.x
  • @RuiBarradas:我发现在~ lambda 函数中使用.x 效果更好,因为它与magrittr 管道%&gt;% 中使用的. 区别开来。考虑mtcars %&gt;% map_at( ncol(.), ~.x*100 )。以这种方式编写它可以立即清楚哪个代词与管道相关联,哪个代词与 lambda 函数相关联。
【解决方案2】:

我们可以直接使用compose(),不用公式语法:

library(tidyverse)

x <- list(mtcars, tibble::as_tibble(iris), c("x", "y", "z"))

map(x, compose(first, class))
#> [[1]]
#> [1] "data.frame"
#> 
#> [[2]]
#> [1] "tbl_df"
#> 
#> [[3]]
#> [1] "character"

reprex package (v2.0.0) 于 2021-06-30 创建

【讨论】:

    【解决方案3】:

    来自?compose

    compose(..., .dir = c("backward", "forward"))

    ... 按顺序应用的函数(默认从右到左)等...

    .dir 如果为“backward”(默认值),则函数以相反的顺序调用,从右到左,这在数学中是常规的。如果是“前进”,则从左到右调用它们。

    所以我们只需要反转函数顺序。同样compose 不知道i=1L 属于哪个函数,因此compose 将在这种情况下将其附加到最后一个函数class,因此我们需要将i=1L 明确定义为预期的函数。

    purrr::map(.x = x, .f = purrr::compose(~.x[[1]], class))
    [[1]]
    [1] "data.frame"
    
    [[2]]
    [1] "tbl_df"
    
    [[3]]
    [1] "character"
    

    【讨论】:

      猜你喜欢
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-19
      • 2021-06-09
      • 1970-01-01
      相关资源
      最近更新 更多