首页 > 解决方案 > R:purrr 理解 purrr 提取函数

问题描述

这里是一个简单的三层嵌套列表,即ob层,每层包含两个v层列表;v 级别,包含一个或两个 s 级别对象,以及 s 级别,每个对象都包含一个字符向量。

test_lst <- list(ob1 = list(v1 = list(s1 = "X", s2 = paste0("A", 1:3)), v2 =  paste0("A", 4:8)), 
                 ob2 = list(v1 = list(s1 = "X", s2 = paste0("A", 9:11)), v2 =  paste0("A", 12:16)))

我试图了解如何使用 purrr 的映射函数按名称提取来访问此列表的各个级别。

提取的帮助文件提供了一个示例,该示例使用在顶层没有名称的列表的名称进行提取。在此示例中,提取函数跳过顶层并使用名称在第二层查找元素。

l1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))
l1 %>% map("a", .default = "???")

第二个示例没有名称并且按位置索引。然而,同样,位置是列表的每个顶级元素中的位置。

l2 <- list(
 list(num = 1:3,     letters[1:3]),
 list(num = 101:103, letters[4:6]),
 list()
)
l2 %>% map(c(2, 2))

在上面的第一个示例中,假设顶层被命名。怎么了?

l1 <- list(one = list(a = 1L), two = list(a = NULL, b = 2L), three = list(b = 3L))
l1 %>% map("a", .default = "???")

结果不变。所以我期待结果

map(test_lst, c("v1", "s2"))

同样跳过顶级名称并返回等效的

lapply(c("ob1", "ob2"), function(X)test_lst[[X]][["v1"]][["s2"]])

[[1]]
[1] "A1" "A2" "A3"

[[2]]
[1] "A9"  "A10" "A11

但事实并非如此。反而,

find_vars <- function(meta){
map_chr(meta, c("v1", "s2")) -> var_vecs
var_vecs
}

find_vars(meta = test_lst)

产生以下错误:

 Error: Result 1 must be a single string, not a character vector of length 3
Call `rlang::last_error()` to see a backtrace 
7. stop(cnd) 
6. abort(message, x = x, expected = expected, actual = actual, what = what, 
    arg = arg, ..., .subclass = c(.subclass, "purrr_error_bad_type")) 
5. stop_bad_type(x, expected, actual = actual, what = what, arg = arg, 
    recycle = recycle, message = message, .subclass = c(.subclass, 
        "purrr_error_bad_vector")) 
4. stop_bad_vector(x, expected_ptype, expected_length, what = what, 
    arg = arg, index = index, ..., recycle = recycle, message = message, 
    .subclass = c(.subclass, "purrr_error_bad_element_vector")) 
3. purrr:::stop_bad_element_vector(c("A1", "A2", "A3"), 1, character(0), 
    1, what = "Result", arg = NULL, recycle = FALSE) 
2. map_chr(meta, c("v1", "s2")) 
1. find_vars(meta = test_lst) 

> rlang::last_error()
<error>
message: Result 1 must be a single string, not a character vector of length 3
class:   `purrr_error_bad_element_vector`
backtrace:
 1. global::find_vars(meta = test_lst)
 3. purrr:::stop_bad_element_vector(...)
 4. purrr:::stop_bad_vector(...)
 5. purrr:::stop_bad_type(...)
Call `rlang::last_trace()` to see the full backtrace
> rlang::last_trace()
    x
 1. +-global::find_vars(meta = test_lst)
 2. | \-purrr::map_chr(meta, c("v1", "s2"))
 3. \-purrr:::stop_bad_element_vector(...)
 4.   \-purrr:::stop_bad_vector(...)
 5.     \-purrr:::stop_bad_type(...)

我想了解:

标签: riterationnested-listspurrrextraction

解决方案


如果我们要提取,然后使用pluck

pluck(test_lst, c("v1", "s2"))

关于error,期望根据文档map_chr返回一个字符vector

map_lgl()、map_int()、map_dbl() 和 map_chr() 各自返回一个指定类型的原子向量(或尝试死)。

但这里的输出是一个`list. 考虑以下示例

map(test_lst, c("v1", "s2")) %>%
           map_chr(toString)
#         ob1            ob2 
#"A1, A2, A3" "A9, A10, A11" 

在将组件提取为 a 之后list,我们paste将元素转换为其中的单个字符串map_chr,现在将其展平为 a vector。但是,如果打算将所有内容都返回为 a vector,则不允许

map(test_lst, c("v1", "s2")) %>% 
        map_chr(I)

错误:结果 1 必须是单个字符串,而不是类AsIs 和长度为 3 的向量调用rlang::last_error()查看回溯


推荐阅读