使用purrr的map函数的输入,在R中创建一个以命名列表形式输出的方法。

44

我正在使用R语言中的purrr包的map函数,该函数的输出是一个列表。现在我希望输出列表根据输入命名。以下是示例。

input <- c("a", "b", "c")
output <- purrr::map(input, function(x) {paste0("test-", x)})

我想要通过以下方式访问列表中的元素:

output$a
或者。
output$b

这是通过 base::Map 默认完成的:output2 <- Map(function(x) {paste0("test-", x)}, input) - andycraig
3个回答

42

我们只需要为list命名即可。

names(output) <- input

然后根据名称提取元素

output$a
#[1] "test-a"
如果需要使用tidyverse完成此操作。
library(tidyverse)
output <- map(input, ~paste0('test-', .)) %>% 
                                setNames(input)

2
FYI,purrrrlang 导入 set_names() 函数。这是为了这个原因。并不是说 base::setNames() 有什么显著的区别... - Anders Swanson
10
有显著的差异,特别是您可以使用x %>% set_names() %>% map(fn)来解决这个问题,这是推荐的解决方案。 - Lionel Henry

35

3
太棒了。我们提前设置了名称。这也适用于 map_dfc,并避免了在映射后设置名称时出现的“重复名称的重命名警告”。 - vinnief

31

更新

现在在2020年,@mihagazvoda的答案描述了正确的方法:在应用map之前简单地set_names

c("a", "b", "c") %>% 
    purrr::set_names() %>% 
    purrr::map(~paste0('test-', .))

过时的回答

已接受的解决方案有效,但存在重复参数 (input),可能会在使用管道和 %>% 时导致错误并中断流程。

另一种替代方案是更加充分地利用 %>% 运算符的功能。

1:5 %>% { set_names(map(., ~ .x + 3), .) } %>% print # ... or something else

这个从管道获取参数的方法还缺少一些美观。一个替代方案可以是一个小的辅助方法,例如:

map_named = function(x, ...) map(x, ...) %>% set_names(x)

1:5 %>% map_named(~ .x + 1)

这看起来已经更漂亮和优雅了。这将是我的首选解决方案。

最后,如果参数是字符或整数向量,我们甚至可以覆盖purrr :: map,并在这种情况下生成一个命名的列表。

map = function(x, ...){
    if (is.integer(x) | is.character(x)) {
        purrr::map(x, ...) %>% set_names(x)
    }else {
        purrr::map(x, ...) 
    }
}

1 : 5 %>% map(~ .x + 1)

然而,最佳解决方案是如果purrr可以直接实现这样的行为。


那将是很棒的!你不应该提出这样的拉取请求吗?或者他们有一个不采用这种方式的好理由吗? - Dan Chaltiel
2
我的直觉是,purrr 维护者不喜欢它,因为它会根据输入创建不同的语义。我想他们更喜欢一些更明确的方法,比如使用参数,但这也支持用例。此外,我猜在相当多的情况下,它会破坏向后兼容性。但是,当然,为什么不询问一下,请参见 https://github.com/tidyverse/purrr/issues/691。 - Holger Brandl
推荐的解决方案(一年后由@mihagazvoda添加)显示确实有一种咕噜咕噜的方法来完成这个任务。 - vinnief
确实。我不想删除这个答案,而是将对这个答案的赞投给 @mihagazvoda。有没有一种 stackoverflow 的方法可以这样做? - Holger Brandl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接