Purrr's Modify-In Function

Viewed 119

I'm trying to use purrr's modify_in to modify elements of a list. An example of the list:

tib_list <- map(1:3, ~ tibble(col_one = runif(5),
    col_two = runif(5), col_three = runif(5)))

Let's say I want to change elements 2 and 3 of the list to unselect col_one. I imagined doing this:

modify_in(tib_list, 2:length(tib_list), ~ select(.x, -col_one) 

But this yields an error. I then thought of doing something like this, but this ends up duplicating the list

map(1:3, ~ modify_in(tib_list, .x, ~ select(.x, -col_one)) 
3 Answers

I think you wanted to use modify_at which lets you specify either element names or positions. modify_in allows us to use only one position like purrr::pluck.

library(tidyverse)

tib_list <- map(1:3, ~ tibble(col_one = runif(5), col_two = runif(5), col_three = runif(5)))

modify_at(tib_list, c(2,3), ~ select(.x, -col_one))
#> [[1]]
#> # A tibble: 5 x 3
#>   col_one col_two col_three
#>     <dbl>   <dbl>     <dbl>
#> 1   0.190   0.599     0.824
#> 2   0.214   0.172     0.106
#> 3   0.236   0.666     0.584
#> 4   0.373   0.903     0.252
#> 5   0.875   0.196     0.643
#> 
#> [[2]]
#> # A tibble: 5 x 2
#>   col_two col_three
#>     <dbl>     <dbl>
#> 1   0.513     0.113
#> 2   0.893     0.377
#> 3   0.275     0.675
#> 4   0.529     0.612
#> 5   0.745     0.405
#> 
#> [[3]]
#> # A tibble: 5 x 2
#>   col_two col_three
#>     <dbl>     <dbl>
#> 1   0.470     0.789
#> 2   0.181     0.289
#> 3   0.680     0.213
#> 4   0.772     0.114
#> 5   0.314     0.895

Created on 2021-08-27 by the reprex package (v0.3.0)

We can use modify_in with one position, but supplying a vector such as c(2,3) would mean that we want to access the third element of the second parent element in a nested list. This is why we see the error below.

# works
modify_in(tib_list, 2, ~ select(.x, -col_one))

#> [[1]]
#> # A tibble: 5 x 3
#>   col_one col_two col_three
#>     <dbl>   <dbl>     <dbl>
#> 1   0.109  0.697     0.0343
#> 2   0.304  0.645     0.851 
#> 3   0.530  0.786     0.600 
#> 4   0.708  0.0324    0.605 
#> 5   0.898  0.232     0.567 
#> 
#> [[2]]
#> # A tibble: 5 x 2
#>   col_two col_three
#>     <dbl>     <dbl>
#> 1  0.766     0.157 
#> 2  0.0569    0.0422
#> 3  0.943     0.0850
#> 4  0.947     0.0806
#> 5  0.761     0.297 
#> 
#> [[3]]
#> # A tibble: 5 x 3
#>   col_one col_two col_three
#>     <dbl>   <dbl>     <dbl>
#> 1   0.878   0.864     0.540
#> 2   0.168   0.745     0.120
#> 3   0.943   0.338     0.535
#> 4   0.353   0.478     0.204
#> 5   0.267   0.669     0.478

# doesn't work
modify_in(tib_list, c(2,3), ~ select(.x, -col_one))

#> Error in UseMethod("select"): no applicable method for 'select' applied to an object of class "c('double', 'numeric')"

I never used modify_in, but you could use

library(purrr)
library(dplyr)

tib_list %>% 
  imap(~ if (.y > 1) { select(.x, -col_one) } else { .x })

to get

[[1]]
# A tibble: 5 x 3
  col_one col_two col_three
    <dbl>   <dbl>     <dbl>
1   0.710   0.189    0.644 
2   0.217   0.946    0.955 
3   0.590   0.770    0.0180
4   0.135   0.101    0.888 
5   0.640   0.645    0.346 

[[2]]
# A tibble: 5 x 2
  col_two col_three
    <dbl>     <dbl>
1   0.267    0.926 
2   0.456    0.0902
3   0.659    0.707 
4   0.421    0.0451
5   0.801    0.220 

[[3]]
# A tibble: 5 x 2
  col_two col_three
    <dbl>     <dbl>
1   0.437     0.649
2   0.256     0.466
3   0.331     0.594
4   0.586     0.558
5   0.625     0.444

We can use modify_if

modify_if(tib_list,.f =  ~ .x %>% select(-col_one), 
       .p = seq_along(tib_list) != 1)

-output

[[1]]
# A tibble: 5 x 3
  col_one col_two col_three
    <dbl>   <dbl>     <dbl>
1   0.819   0.666    0.384 
2   0.183   0.549    0.0211
3   0.374   0.240    0.252 
4   0.359   0.913    0.792 
5   0.515   0.402    0.217 

[[2]]
# A tibble: 5 x 2
  col_two col_three
    <dbl>     <dbl>
1   0.696    0.0269
2   0.433    0.147 
3   0.235    0.743 
4   0.589    0.748 
5   0.635    0.851 

[[3]]
# A tibble: 5 x 2
  col_two col_three
    <dbl>     <dbl>
1  0.707      0.976
2  0.0966     0.130
3  0.574      0.572
4  0.854      0.680
5  0.819      0.582
Related