【问题标题】:How to replace a modifying for loop by purrr如何通过 purrr 替换修改 for 循环
【发布时间】:2019-12-01 04:54:48
【问题描述】:

我想用 purrr 替代品替换一个简单的 for 循环。如何编码并保持对象的原始结构

这是我的例子:

my_list <- list(
      a = list(
        list(
          aaa = c(1:3),
          aab = c(4:6), 
          aac = c(7:9)),
        list(
          aaa = c(10:12),
          aab = c(13:15), 
          aac = c(16:18)),
        list(
          aaa = c(19:21),
          aab = c(22:24), 
          aac = c(25:27))
      ))

和我原来的解决方案

x <- purrr::map_lgl(my_list$a, .f = ~ !is.null(.x$aaa))

my_list1 <- my_list
for (i in which(x)) {
      my_list1$a[[i]]$aaa <- 99
}
str(my_list1)

但是,我也想用 purrr 解决方案替换我的 for 循环。我尝试了类似的方法,但 map 总是返回一个新列表,而不是仅仅更新它

my_list2 <- map(c(1, 3),
        function(x){
          my_list[["a"]][[x]][["aab"]] <- 99
          return(my_list)
        }
)
str(my_list2)

修改在这种情况下应该更适用,但我也不能让它工作。

my_list3 <- purrr::map(
      .x = which(x), 
      .f = function(i = .x) {
        purrr::modify_in(.x = my_list, 
                         .where = list("a", i, "aaa"), 
                         .f = ~99)
      }
)
str(my_list3)

新列表的结构应该与初始列表相同:

# str(my_list)
List of 1
 $ a:List of 3
  ..$ :List of 3
  .. ..$ aaa: int [1:3] 1 2 3
  .. ..$ aab: int [1:3] 4 5 6
  .. ..$ aac: int [1:3] 7 8 9
  ..$ :List of 2
  .. ..$ aab: int [1:3] 13 14 15
  .. ..$ aac: int [1:3] 16 17 18
  ..$ :List of 3
  .. ..$ aaa: int [1:3] 19 20 21
  .. ..$ aab: int [1:3] 22 23 24
  .. ..$ aac: int [1:3] 25 26 27

# str(my_list1) is correct
List of 1
 $ a:List of 3
  ..$ :List of 3
  .. ..$ aaa: num 99
  .. ..$ aab: int [1:3] 4 5 6
  .. ..$ aac: int [1:3] 7 8 9
  ..$ :List of 2
  .. ..$ aab: int [1:3] 13 14 15
  .. ..$ aac: int [1:3] 16 17 18
  ..$ :List of 3
  .. ..$ aaa: num 99
  .. ..$ aab: int [1:3] 22 23 24
  .. ..$ aac: int [1:3] 25 26 27

# str(my_list2) or str (my_list3) is not correct
List of 2
 $ :List of 1
  ..$ a:List of 3
  .. ..$ :List of 3
  .. .. ..$ aaa: num 99
  .. .. ..$ aab: int [1:3] 4 5 6
  .. .. ..$ aac: int [1:3] 7 8 9
  .. ..$ :List of 2
  .. .. ..$ aab: int [1:3] 13 14 15
  .. .. ..$ aac: int [1:3] 16 17 18
  .. ..$ :List of 3
  .. .. ..$ aaa: int [1:3] 19 20 21
  .. .. ..$ aab: int [1:3] 22 23 24
  .. .. ..$ aac: int [1:3] 25 26 27
 $ :List of 1
  ..$ a:List of 3
  .. ..$ :List of 3
  .. .. ..$ aaa: int [1:3] 1 2 3
  .. .. ..$ aab: int [1:3] 4 5 6
  .. .. ..$ aac: int [1:3] 7 8 9
  .. ..$ :List of 2
  .. .. ..$ aab: int [1:3] 13 14 15
  .. .. ..$ aac: int [1:3] 16 17 18
  .. ..$ :List of 3
  .. .. ..$ aaa: num 99
  .. .. ..$ aab: int [1:3] 22 23 24
  .. .. ..$ aac: int [1:3] 25 26 27

任何提示我在 purrr 中出错的地方?

【问题讨论】:

    标签: r purrr


    【解决方案1】:

    一种方法是使用map 并更改每个列表中的单个元素。

    my_list[["a"]][x] <- purrr::map(my_list[["a"]][x], ~{.[["aaa"]] <- 99;.})
    
    
    my_list
    #$a
    #$a[[1]]
    #$a[[1]]$aaa
    #[1] 99
    
    #$a[[1]]$aab
    #[1] 4 5 6
    
    #$a[[1]]$aac
    #[1] 7 8 9
    
    
    #$a[[2]]
    #$a[[2]]$aaa
    #[1] 99
    
    #$a[[2]]$aab
    #[1] 13 14 15
    
    #$a[[2]]$aac
    #[1] 16 17 18
    #......
    

    这与在基础 R 中使用 lapply 相同

    my_list[["a"]][x] <- lapply(my_list[["a"]][x], function(x) {x[["aaa"]] <- 99;x})
    

    【讨论】:

    • 感谢您的建议,但无论我的 x 向量如何,您都可以更改所有 aaa。我只是想在特定情况下更改它。
    • @Mat 你可以使用x 子集my_list 。更新了答案。
    【解决方案2】:

    鉴于要修改的列表组件位于嵌套的第二层,您也可以通过modify_depth直接访问它们:

    library(purrr)
    
    my_list <- modify_depth(my_list, 2, ~list_modify(.x, aaa = 99))
    
    str(my_list)
    #> List of 1
    #>  $ a:List of 3
    #>   ..$ :List of 3
    #>   .. ..$ aaa: num 99
    #>   .. ..$ aab: int [1:3] 4 5 6
    #>   .. ..$ aac: int [1:3] 7 8 9
    #>   ..$ :List of 3
    #>   .. ..$ aaa: num 99
    #>   .. ..$ aab: int [1:3] 13 14 15
    #>   .. ..$ aac: int [1:3] 16 17 18
    #>   ..$ :List of 3
    #>   .. ..$ aaa: num 99
    #>   .. ..$ aab: int [1:3] 22 23 24
    #>   .. ..$ aac: int [1:3] 25 26 27
    

    注意:这也适用于第一个列表级别的多个列表组件(例如 $a$b、...),而无需添加额外的迭代步骤。


    编辑:如modify_depth的文档中所列:

    modify_depth(x, 2, fun) 等价于 x

    为了仅替换第二个嵌套级别的列表组件选择,我们可以将调用重写为更详细的modify_depth

    library(purrr)
    
    ## replace aaa only for components 1 and 3
    modify_loc <- c(TRUE, FALSE, TRUE)
    
    my_list <- modify(my_list, ~imodify(., ~if(modify_loc[.y]) list_modify(.x, aaa = 99) else .x))
    
    str(my_list)
    #> List of 1
    #>  $ a:List of 3
    #>   ..$ :List of 3
    #>   .. ..$ aaa: num 99
    #>   .. ..$ aab: int [1:3] 4 5 6
    #>   .. ..$ aac: int [1:3] 7 8 9
    #>   ..$ :List of 3
    #>   .. ..$ aaa: int [1:3] 10 11 12
    #>   .. ..$ aab: int [1:3] 13 14 15
    #>   .. ..$ aac: int [1:3] 16 17 18
    #>   ..$ :List of 3
    #>   .. ..$ aaa: num 99
    #>   .. ..$ aab: int [1:3] 22 23 24
    #>   .. ..$ aac: int [1:3] 25 26 27
    

    【讨论】:

    • 感谢您的建议,但无论我的 x 向量如何,您都可以更改所有 aaa。我只是想在特定情况下更改它。在我看来,我需要像 modify_depth_if() 这样的东西。
    • @Mat:查看编辑后的回复,这使得它不如原来的 modify_depth 调用简洁,并且不同的方法可能更直接
    • 感谢您的解决方案,Joris!我已经对另一个很满意,但两者都完成了工作:)
    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 2018-07-15
    • 2020-08-30
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    相关资源
    最近更新 更多