У меня есть список, в котором каждый элемент сам по себе является именованным списком атрибутов, вид вывода, который вы получите из типичного JSON:
l <- list(
list(
"attr1" = 1,
"attr2" = "x",
"attr3" = 3:4
),
list(
"attr1" = 5,
"attr2" = "y",
"attr3" = 7:9
),
list(
"attr1" = 10,
"attr2" = "z",
"attr3" = 12
)
)
Некоторые из атрибутов имеют одиночное значение того же типа (например, attr1
и attr2
), а некоторые сами являются векторами, различной длины (например, attr3
).
Я хотел бы использовать purrr
для преобразования этого списка во фрейм данных, где attr1
и attr2
- это «обычные» столбцы, а attr3
- это список столбец:
tibble(
attr1 = c(1, 5, 10),
attr2 = c("x", "y", "z"),
attr3 = list(c(3:4), c(7:9), 12)
)
# A tibble: 3 x 3
attr1 attr2 attr3
<dbl> <chr> <list>
1 1 x <int [2]>
2 5 y <int [3]>
3 10 z <dbl [1]>
Суть в том, что у меня много атрибутов, и я понятия не имею, какие из них являются единственными и являются списками
Этот простой подход, конечно, потерпит неудачу из-за attr3
:
attrs <- names(l[[1]])
get_element_details <- function(element, attrs) {
element_list <- map(attrs, function(attr) pluck(element, attr))
names(element_list) <- attrs
element_list
}
df <- l %>% map_dfr(get_element_details, attrs)
Ошибка: аргумент 3 должен иметь длину 1, а не 2
Этот подход работает, но я должен заранее знать, какие атрибуты должны быть единичными, а какие списки. Я использую именованный вектор attrs_dict
, что-то вроде словаря Python, с которым функция pluck_wrapper
обращается, чтобы вернуть единственное значение или список:
attrs_dict <- c("attr1" = FALSE, "attr2" = FALSE, "attr3" = TRUE)
pluck_wrapper <- function(element, attr, attrs_dict) {
res <- pluck(element, attr)
if (attrs_dict[attr]) {
return(list(res))
}
return(res)
}
get_element_details <- function(element, attrs_dict) {
attrs <- names(attrs_dict)
element_list <- map(attrs, function(attr) pluck_wrapper(element, attr, attrs_dict))
names(element_list) <- attrs
element_list
}
df <- l %>% map_dfr(get_element_details, attrs_dict)
df
# A tibble: 3 x 3
attr1 attr2 attr3
<dbl> <chr> <list>
1 1 x <int [2]>
2 5 y <int [3]>
3 10 z <dbl [1]>
Увы, как я уже сказал, что мне делать, если у меня много атрибутов, и я заранее не знаю, которые являются единичными, а какие списками? (хотя можно предположить, что все они существуют)
Я, конечно, всегда могу вернуть list(pluck(...))
, но я получу:
get_element_details <- function(element, attrs) {
element_list <- map(attrs, function(attr) list(pluck(element, attr)))
names(element_list) <- attrs
element_list
}
df <- l %>% map_dfr(get_element_details, attrs)
df
# A tibble: 3 x 3
attr1 attr2 attr3
<list> <list> <list>
1 <dbl [1]> <chr [1]> <int [2]>
2 <dbl [1]> <chr [1]> <int [3]>
3 <dbl [1]> <chr [1]> <dbl [1]>
Что я понятия не имею, как упростить (легко), но это также было бы хорошим направлением.