Можно ли извлечь несколько элементов из списка в R с помощью map()?

Используя различные функции map() из пакета purrr, вы можете передать целое число или строку символов в функцию и извлечь элемент из подсписка. Они работают так, как я ожидал:

listy <- list(A = list("silence", "cats", X = list(Aa = "dogs", "birds")),
              B = list("silence", "fish-head", Y = list(Bb = "fish-face", "squirrel")))

> str(listy)
List of 2
 $ A:List of 3
  ..$  : chr "silence"
  ..$  : chr "cats"
  ..$ X:List of 2
  .. ..$ Aa: chr "dogs"
  .. ..$   : chr "birds"
 $ B:List of 3
  ..$  : chr "silence"
  ..$  : chr "fish-head"
  ..$ Y:List of 2
  .. ..$ Bb: chr "fish-face"
  .. ..$   : chr "squirrel"

list1 <- listy %>% map(1) %>% str  # returns "silence" from A and B
list2 <- listy %>% map(2) %>% str  # returns "cats" and "fish-head"
list3 <- listy %>% map(c(3, 1)) %>% str # returns "dogs" and "fish-face" from the lists X and Y within the list.

Мой вопрос: как извлечь более одного элемента из этого списка? Если бы я хотел «тишины» от A и B, а «кошки» и «рыбья голова» от A и B (другими словами, элементы 1 и 2 как A, так и B), возможно ли это с map()? И если нет, то как лучше всего это сделать?

Вот что, как я думал, сработает:

list4 <- listy %>% map(1, 2) %>% str

Где 1 относится к первому элементу из каждого подсписка, а 2 ко второму. Но это возвращает то же самое, что и list1 выше. Использование c(1, 2) не работает, поскольку оно относится к вложенной структуре (например, [[1]][[2]]). Я просмотрел документацию и несколько примеров, найденных в Google, но не повезло. Любые идеи?

Обновление: я должен объяснить, что в идеале я хотел бы иметь возможность выбирать элементы по имени, как в «тишине». Однако это, похоже, работает не слишком хорошо. (У меня есть несколько больших списков, в которых меняется положение нужных мне элементов)


person RobertMyles    schedule 01.08.2016    source источник
comment
Чтобы выбрать элементы по имени, вам, вероятно, придется назвать элементы списка. Работа с именованными списками, вероятно, является правильным решением. Затем вы можете заменить 1: 2 в наших ответах вектором имен элементов без каких-либо дальнейших изменений.   -  person lmo    schedule 01.08.2016


Ответы (2)


Что-то вроде этого?

library(purrr)
listy %>% map(., function(x) c(x[[1]], x[[2]]))

$A
[1] "silence" "cats"   

$B
[1] "silence"   "fish-head"

Чтобы получить вывод в виде data.frame,

listy %>% map_df(., function(x) c(x[[1]], x[[2]]))

# A tibble: 2 x 2
        A         B
    <chr>     <chr>
1 silence   silence
2    cats fish-head

Или, как предложил @Richard Scriven,

map(listy, ~ unlist(.[1:2]))
person Sumedh    schedule 01.08.2016
comment
Или даже map(listy, ~ unlist(.[1:2])) - person Rich Scriven; 01.08.2016
comment
Спасибо, Сумед и Ричард, это отвечает на мой вопрос. В идеале я хотел бы избежать нотации x[[1]], и, поскольку я редактировал свой вопрос, было бы здорово выбрать элементы по имени (например, карта (список, тишина)), как в виньетке мурлыканья. Любые идеи о том, как это сделать? Если бы вы могли добавить это к своему ответу, я бы принял его как ответ. - person RobertMyles; 01.08.2016
comment
Моя ошибка, можно выбрать элементы, используя ответ @Sumedh и строки. Спасибо! - person RobertMyles; 01.08.2016

Вот два варианта в базе R с lapply.

Чтобы сохранить структуру вложенного списка, используйте

lapply(listy, "[", 1:2)
$A
$A[[1]]
[1] "silence"

$A[[2]]
[1] "cats"


$B
$B[[1]]
[1] "silence"

$B[[2]]
[1] "fish-head"

Чтобы вернуть единый список векторов, используйте

lapply(listy, function(i) unlist(i[1:2]))
$A

"silence"    "cats" 

$B

  "silence" "fish-head" 

Вы можете обернуть второй метод в data.frame, чтобы вернуть data.frame.

data.frame(lapply(listy, function(i) unlist(i[1:2])))
        A         B
1 silence   silence
2    cats fish-head
person lmo    schedule 01.08.2016