извлекать векторы с одинаковыми именами из вложенных списков, где имена списков меняются? Используете мурлыкание? - PullRequest
1 голос
/ 15 января 2020

Мне нужно работать с некоторыми данными, которые находятся в рекурсивных списках, таких как этот (упрощенный воспроизводимый пример ниже):

groups
#> $group1
#> $group1$countries
#> [1] "USA" "JPN"
#> 
#> 
#> $group2
#> $group2$countries
#> [1] "AUS" "GBR"

Код для ввода данных ниже:

chars <- c("USA", "JPN")
chars2 <- c("AUS", "GBR")

group1 <- list(countries = chars)
group2 <- list(countries = chars2)

groups <- list(group1 = group1, group2 = group2)
groups

I ' Я пытаюсь понять, как извлечь векторы, которые есть в списках, без необходимости вручную писать строку кода для каждой группы. Приведенный ниже код работает, но в моем примере большое количество групп (и количество групп изменится), поэтому было бы неплохо решить, как извлечь все векторы более эффективным образом. Это метод грубой силы, который работает:

countries1 <- groups$group1$countries
countries2 <- groups$group2$countries

В этом примере вектор нижнего уровня, который я пытаюсь извлечь, всегда называется countries, но списки, которые они содержат в имени изменения , отличающийся только нумерацией.

Будет ли простое мурлыканье? Или решение Tidyverse? Или другое решение?

Ответы [ 4 ]

1 голос
/ 15 января 2020

Добавьте некоторые дополнительные случаи в ваш список

groups[["group3"]] <- list()
groups[["group4"]] <- list(foo = letters[1:2])
groups[["group5"]] <- list(foo = letters[1:2], countries = LETTERS[1:2])

Вот функция, которая отображает любой список только на элементы с именем "стран"; он возвращает NULL, если нет элементов

fun = function(x)
    x[["countries"]]

Сопоставьте ваш исходный список с теми элементами, которые вам интересны

interesting <- Map(fun, groups)

Затем преобразуйте их в data.frame используя комбинацию unlist() и rep()

df <- data.frame(
    country = unlist(interesting, use.names = FALSE),
    name = rep(names(interesting), lengths(interesting))
)

В качестве альтернативы используйте синтаксис tidy, например,

interesting %>% 
    tibble(group = names(.), value = .) %>% 
    unnest("value")

Выходные данные

# A tibble: 6 x 2
  group  value
  <chr>  <chr>
1 group1 USA
2 group1 JPN
3 group2 AUS
4 group2 GBR
5 group5 A
6 group5 B

Если Есть дополнительные проблемы при разборе отдельных элементов groups, затем измените fun, например,

fun = function(x)
    as.character(x[["countries"]])
1 голос
/ 15 января 2020

Вы можете просто преобразовать свой вложенный список в data.frame, а затем unnest столбец страны.

library(dplyr)
library(tidyr)
groups %>% 
  tibble(group = names(groups),
         country = .) %>% 
  unnest(country) %>% 
  unnest(country)
#> # A tibble: 4 x 2
#>   group  country
#>   <chr>  <chr>  
#> 1 group1 USA    
#> 2 group1 JPN    
#> 3 group2 AUS    
#> 4 group2 GBR

Создано в 2020-01-15 пакетом представ. (v0.3.0)

Поскольку страны скрыты на 2 слоя глубиной, вам придется дважды запустить unnest. В противном случае я думаю, что это просто.

1 голос
/ 15 января 2020

Это поместит вывод в список, который будет обрабатывать любое количество групп

countries <- unlist(groups, recursive = FALSE)
names(countries) <- sub("^\\w+(\\d+)\\.(\\w+)", "\\2\\1", names(countries), perl = TRUE)

> countries
$countries1
[1] "USA" "JPN"

$countries2
[1] "AUS" "GBR"
0 голосов
/ 15 января 2020

Если вы действительно хотите, чтобы каждый вектор представлял собой объект в вашей глобальной среде, сработает комбинация purrr :: map2 / walk и list2env. Для того, чтобы это работало, мы должны сначала дать отдельным странам названия в списке, в противном случае list2env просто перезаписывает один и тот же объект снова и снова.

library(purrr)
groups <- 
  map2(groups, 1:length(groups), ~setNames(.x, paste0(names(.x), .y)))
walk(groups, ~list2env(. , envir = .GlobalEnv))

Это приведет к тому же результату, что и вы. описывают в вашем вопросе. Я не уверен, однако, является ли это лучшим решением для бесперебойного рабочего процесса, так как я не знаю, куда вы идете с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...