使用Modify_depth和Modify_if(purrr)根据深度和if条件将元素插入列表中

时间:2019-05-25 09:06:31

标签: r dplyr purrr

我正在学习一些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 个答案:

答案 0 :(得分:1)

这似乎有效。 map_iffunction(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