我正在使用R语言中的purrr包的map函数,该函数的输出是一个列表。现在我希望输出列表根据输入命名。以下是示例。
input <- c("a", "b", "c")
output <- purrr::map(input, function(x) {paste0("test-", x)})
我想要通过以下方式访问列表中的元素:
output$a
或者。output$b
我们只需要为list
命名即可。
names(output) <- input
然后根据名称提取元素
output$a
#[1] "test-a"
如果需要使用tidyverse
完成此操作。library(tidyverse)
output <- map(input, ~paste0('test-', .)) %>%
setNames(input)
purrr
从 rlang
导入 set_names()
函数。这是为了这个原因。并不是说 base::setNames()
有什么显著的区别... - Anders Swansonx %>% set_names() %>% map(fn)
来解决这个问题,这是推荐的解决方案。 - Lionel Henryc("a", "b", "c") %>%
purrr::set_names() %>%
purrr::map(~paste0('test-', .))
更新
现在在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
可以直接实现这样的行为。
purrr
维护者不喜欢它,因为它会根据输入创建不同的语义。我想他们更喜欢一些更明确的方法,比如使用参数,但这也支持用例。此外,我猜在相当多的情况下,它会破坏向后兼容性。但是,当然,为什么不询问一下,请参见 https://github.com/tidyverse/purrr/issues/691。 - Holger Brandl
base::Map
默认完成的:output2 <- Map(function(x) {paste0("test-", x)}, input)
。 - andycraig