首页 > 解决方案 > 使用 purrr::pmap 来利用 .f 列表名称

问题描述

以下工作正常:

pmap_dbl(iris, ~ ..1 + ..2 + ..3 + ..4)

的文档.l提供了A list of lists. ... List names will be used if present.. 这表明您应该能够使用列表名称(即列名称)。然而:

pmap_dbl(iris, ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width)
Error in .f(Sepal.Length = .l[[c(1L, i)]], Sepal.Width = .l[[c(2L, i)]],  : 
  object 'Sepal.Length' not found

在实践中如何利用列表名称?

标签: rpurrr

解决方案


公式参数~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width被传递给purrr::as_mapper.

purrr::as_mapper(~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width)
# function (..., .x = ..1, .y = ..2, . = ..1) 
# Sepal.Length + Sepal.Width + Petal.Length + Petal.Width

你可以看到这个函数没有直接的方法知道这些变量是什么。

我可以想到 3 种方法来解决这个问题。我将使用@zacdav 的示例,因为它比您的更紧凑和可读:

named_list <- list(one = c(1, 1),
                   two = c(2, 2),
                   three = c(3, 3))

明确定义

您可以明确定义这些变量,如@zacdav's answer中所示,它将起作用。


探索点论点

有一种方法可以通过...返回的函数的参数访问命名参数as_mapper

当名称可用时,函数的参数会被命名,正如文档所说的那样。

这就解释了为什么pmap(named_list, function(x,y,z) x+y+z)会因错误而失败:

未使用的参数(一个 = .l[[c(1, i)]],两个 = .l[[c(2, i)]],三个 = .l[[c(3, i)]])

看:

pmap(named_list, ~names(list(...)))
# [[1]]
# [1] "one"   "two"   "three"
# 
# [[2]]
# [1] "one"   "two"   "three"

pmap(unname(named_list), function(x,y,z) x+y+z)另一方面会正常工作)

所以这将起作用:

pmap(named_list, ~ with(list(...), one + two + three))
# [[1]]
# [1] 6
# 
# [[2]]
# [1] 6 

使用 pryr::f

pryr为函数定义提供了一个简洁的快捷方式pryr::f

library(pryr)
f(one + two + three)
# function (one, three, two) 
# one + two + three

pmap(named_list, f(one + two + three))
# [[1]]
# [1] 6
# 
# [[2]]
# [1] 6
# 

但是在使用它时要小心,全局变量仍将显示为参数,而函数将或不会包含在参数中,具体取决于它们的调用方式。例如 :

x <- 1
test <- mean
f(test(x) + lapply(iris,test2))
# function (iris, test2, x) 
# test(x) + lapply(iris, test2)

所以这不是一个通用的方法,你应该只在简单的情况下使用它。第二种方法虽然有点小技巧,但将是通用的。

此外f,按字母顺序对参数进行排序,这在处理命名列表时应该不是问题,但在处理部分命名列表时要小心。


推荐阅读