Вставьте элементы в список на основе глубины и условий if, используя modify_depth и modify_if (purrr) - PullRequest
1 голос
/ 25 мая 2019

Я изучаю некоторые purrr команды, в частности семейство функций modify_*. Я пытаюсь добавить price корзины к продуктам, найденным в продуктовом магазине (см. Ниже мои попытки и код ошибки).

library(tidyverse)

Данные

easybuy <- list(
  "5520 N Division St, Spokane, WA 99208, USA",
  list("bananas", "oranges"),
  canned = list("olives", "fish", "jam"),
  list("pork", "beef"),
  list("hammer", "tape")
) %>%
  map(list) %>%
  # name the sublists
  set_names(c("address",
              "fruit",
              "canned",
              "meat",
              "other")) %>%
  # except for address, names the sublists "items"
  modify_at(c(2:5), ~ set_names(.x, "items"))

Взгляните:

glimpse(easybuy)
#> List of 5
#>  $ address:List of 1
#>   ..$ : chr "5520 N Division St, Spokane, WA 99208, USA"
#>  $ fruit  :List of 1
#>   ..$ items:List of 2
#>   .. ..$ : chr "bananas"
#>   .. ..$ : chr "oranges"
#>  $ canned :List of 1
#>   ..$ items:List of 3
#>   .. ..$ : chr "olives"
#>   .. ..$ : chr "fish"
#>   .. ..$ : chr "jam"
#>  $ meat   :List of 1
#>   ..$ items:List of 2
#>   .. ..$ : chr "pork"
#>   .. ..$ : chr "beef"
#>  $ other  :List of 1
#>   ..$ items:List of 2
#>   .. ..$ : chr "hammer"
#>   .. ..$ : chr "tape"

Моя попытка

Идея: углубиться в два и найти «предметы», добавить «цену». Я не уверен, что смогу вложить modify функции, подобные этой.

easybuy %>% 
  modify_depth(2, ~ modify_at(., "items", ~ append("price")))
#> Error: character indexing requires a named object

Желаемая

Я бы хотел следующую структуру ( обратите внимание на добавление «цены» под каждым элементом ):

List of 5
 $ address:List of 1
  ..$ : chr "5520 N Division St, Spokane, WA 99208, USA"
 $ fruit  :List of 1
  ..$ items:List of 2
  .. ..$ :List of 2
  .. .. ..$ : chr "bananas"
  .. .. ..$ : chr "price"
  .. ..$ :List of 2
  .. .. ..$ : chr "oranges"
  .. .. ..$ : chr "price"
 $ canned :List of 1
  ..$ items:List of 3
  .. ..$ :List of 2
  .. .. ..$ : chr "olives"
  .. .. ..$ : chr "price"
  .. ..$ :List of 2
  .. .. ..$ : chr "fish"
  .. .. ..$ : chr "price"
  .. ..$ :List of 2
  .. .. ..$ : chr "jam"
  .. .. ..$ : chr "price"
 $ meat   :List of 1
  ..$ items:List of 2
  .. ..$ :List of 2
  .. .. ..$ : chr "pork"
  .. .. ..$ : chr "price"
  .. ..$ :List of 2
  .. .. ..$ : chr "beef"
  .. .. ..$ : chr "price"
 $ other  :List of 1
  ..$ items:List of 2
  .. ..$ :List of 2
  .. .. ..$ : chr "hammer"
  .. .. ..$ : chr "price"
  .. ..$ :List of 2
  .. .. ..$ : chr "tape"
  .. .. ..$ : chr "price"

1 Ответ

1 голос
/ 26 мая 2019

Это похоже на работу.map_if и function(x) !is.null(names(x)) гарантируют, что изменение произойдет только в том случае, если имя элемента не NULL.~modify_depth(.x, 2, function(y) list(y, "price")) создает необходимый список.

library(tidyverse)

easybuy2 <- easybuy %>%
  map_if(function(x) !is.null(names(x)),
         ~modify_depth(.x, 2, function(y) list(y, "price")))

Вот как выглядит второй элемент.

easybuy2[[2]][[1]]
# [[1]]
# [[1]][[1]]
# [1] "bananas"
# 
# [[1]][[2]]
# [1] "price"
# 
# 
# [[2]]
# [[2]][[1]]
# [1] "oranges"
# 
# [[2]][[2]]
# [1] "price"

Или это также работает.

easybuy3 <- easybuy %>% 
  modify_at(2:5, ~modify_depth(.x, 2, function(y) list(y, "price")))

identical(easybuy2, easybuy3)
# [1] TRUE

Обновление

easybuy4 <- easybuy %>%
  map_if(function(x){
    name <- names(x) 
    if(is.null(name)){
      return(FALSE)
    } else {
      return(name %in% "items")
    }
  },
~modify_depth(.x, 2, function(y) list(y, "price")))

identical(easybuy2, easybuy4)
# [1] TRUE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...