modify() is a short-cut for x[] <- map(x, .f). modify_if() only modifies the elements of .x that satisfy a predicate. map_at() only modifies elements given by names or positions. modify_depth() only modifies elements at a given level of a nested data structure.

modify(.x, .f, ...)

modify_if(.x, .p, .f, ...)

modify_at(.x, .at, .f, ...)

modify_depth(.x, .depth, .f, ..., .ragged = .depth < 0)

Arguments

.x

A list or atomic vector.

.f

A function, formula, or atomic vector.

If a function, it is used as is.

If a formula, e.g. ~ .x + 2, it is converted to a function. There are three ways to refer to the arguments:

  • For a single argument function, use .

  • For a two argument function, use .x and .y

  • For more arguments, use ..1, ..2, ..3 etc

This syntax allows you to create very compact anonymous functions.

If character vector, numeric vector, or list, it is converted to an extractor function. Character vectors index by name and numeric vectors index by position; use a list to index by position and name at different levels. Within a list, wrap strings in get_attr() to extract named attributes. If a component is not present, the value of .default will be returned.

...

Additional arguments passed on to .f.

.p

A single predicate function, a formula describing such a predicate function, or a logical vector of the same length as .x. Alternatively, if the elements of .x are themselves lists of objects, a string indicating the name of a logical element in the inner lists. Only those elements where .p evaluates to TRUE will be modified.

.at

A character vector of names or a numeric vector of positions. Only those elements corresponding to .at will be modified.

.depth

Level of .x to map on. Use a negative value to count up from the lowest level of the list.

  • modify_depth(x, 0, fun) is equivalent to x[] <- fun(x)

  • modify_depth(x, 1, fun) is equivalent to x[] <- map(x, fun)

  • modify_depth(x, 2, fun) is equivalent to x[] <- map(x, ~ map(., fun))

.ragged

If TRUE, will apply to leaves, even if they're not at depth .depth. If FALSE, will throw an error if there are no elements at depth .depth.

Value

An object the same class as .x

Details

These modify the input data structure; it's your responsibility to ensure that the transformation produces a valid output. For example, if you're modifying a data frame, .f must preserve the length of the input.

See also

Other map variants: imap, invoke, lmap, map2, map

Examples

# Convert factors to characters iris %>% map_if(is.factor, as.character) %>% str()
#> Warning: map_if() is deprecated, please use `modify_if()` instead
#> 'data.frame': 150 obs. of 5 variables: #> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... #> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ... #> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ... #> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... #> $ Species : chr "setosa" "setosa" "setosa" "setosa" ...
# Specify which columns to map with a numeric vector of positions: mtcars %>% map_at(c(1, 4, 5), as.character) %>% str()
#> Warning: map_at() is deprecated, please use `modify_at()` instead
#> 'data.frame': 32 obs. of 11 variables: #> $ mpg : chr "21" "21" "22.8" "21.4" ... #> $ cyl : num 6 6 4 6 8 6 8 4 4 6 ... #> $ disp: num 160 160 108 258 360 ... #> $ hp : chr "110" "110" "93" "110" ... #> $ drat: chr "3.9" "3.9" "3.85" "3.08" ... #> $ wt : num 2.62 2.88 2.32 3.21 3.44 ... #> $ qsec: num 16.5 17 18.6 19.4 17 ... #> $ vs : num 0 0 1 1 0 1 0 1 1 1 ... #> $ am : num 1 1 1 0 0 0 0 0 0 0 ... #> $ gear: num 4 4 4 3 3 3 3 4 4 4 ... #> $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
# Or with a vector of names: mtcars %>% map_at(c("cyl", "am"), as.character) %>% str()
#> Warning: map_at() is deprecated, please use `modify_at()` instead
#> 'data.frame': 32 obs. of 11 variables: #> $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ... #> $ cyl : chr "6" "6" "4" "6" ... #> $ disp: num 160 160 108 258 360 ... #> $ hp : num 110 110 93 110 175 105 245 62 95 123 ... #> $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ... #> $ wt : num 2.62 2.88 2.32 3.21 3.44 ... #> $ qsec: num 16.5 17 18.6 19.4 17 ... #> $ vs : num 0 0 1 1 0 1 0 1 1 1 ... #> $ am : chr "1" "1" "1" "0" ... #> $ gear: num 4 4 4 3 3 3 3 4 4 4 ... #> $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
list(x = rbernoulli(100), y = 1:100) %>% transpose() %>% map_if("x", ~ update_list(., y = ~ y * 100)) %>% transpose() %>% simplify_all()
#> Warning: map_if() is deprecated, please use `modify_if()` instead
#> $x #> [1] FALSE TRUE FALSE FALSE FALSE TRUE TRUE TRUE FALSE TRUE TRUE TRUE #> [13] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> [25] TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE TRUE TRUE FALSE TRUE #> [37] TRUE TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE #> [49] FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE TRUE FALSE #> [61] TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE #> [73] TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE TRUE FALSE TRUE FALSE #> [85] TRUE TRUE FALSE TRUE FALSE TRUE TRUE TRUE FALSE TRUE FALSE FALSE #> [97] TRUE FALSE FALSE TRUE #> #> $y #> [1] 1 200 3 4 5 600 700 800 9 1000 1100 1200 #> [13] 13 14 15 1600 17 18 19 20 21 22 23 24 #> [25] 2500 26 27 2800 2900 3000 31 3200 3300 3400 35 3600 #> [37] 3700 3800 3900 40 41 42 43 4400 45 46 4700 48 #> [49] 49 50 5100 52 53 54 55 5600 57 5800 5900 60 #> [61] 6100 6200 63 6400 65 6600 67 68 69 70 7100 72 #> [73] 7300 74 75 7600 7700 7800 79 80 8100 82 8300 84 #> [85] 8500 8600 87 8800 89 9000 9100 9200 93 9400 95 96 #> [97] 9700 98 99 10000 #>
# Modify at specified depth --------------------------- l1 <- list( obj1 = list( prop1 = list(param1 = 1:2, param2 = 3:4), prop2 = list(param1 = 5:6, param2 = 7:8) ), obj2 = list( prop1 = list(param1 = 9:10, param2 = 11:12), prop2 = list(param1 = 12:14, param2 = 15:17) ) ) # In the above list, "obj" is level 1, "prop" is level 2 and "param" # is level 3. To apply sum() on all params, we map it at depth 3: l1 %>% modify_depth(3, sum) %>% str()
#> List of 2 #> $ obj1:List of 2 #> ..$ prop1:List of 2 #> .. ..$ param1: int 3 #> .. ..$ param2: int 7 #> ..$ prop2:List of 2 #> .. ..$ param1: int 11 #> .. ..$ param2: int 15 #> $ obj2:List of 2 #> ..$ prop1:List of 2 #> .. ..$ param1: int 19 #> .. ..$ param2: int 23 #> ..$ prop2:List of 2 #> .. ..$ param1: int 39 #> .. ..$ param2: int 48
# modify() lets us pluck the elements prop1/param2 in obj1 and obj2: l1 %>% modify(c("prop1", "param2")) %>% str()
#> List of 2 #> $ obj1: int [1:2] 3 4 #> $ obj2: int [1:2] 11 12
# But what if we want to pluck all param2 elements? Then we need to # act at a lower level: l1 %>% modify_depth(2, "param2") %>% str()
#> List of 2 #> $ obj1:List of 2 #> ..$ prop1: int [1:2] 3 4 #> ..$ prop2: int [1:2] 7 8 #> $ obj2:List of 2 #> ..$ prop1: int [1:2] 11 12 #> ..$ prop2: int [1:3] 15 16 17
# modify_depth() can be with other purrr functions to make them operate at # a lower level. Here we ask pmap() to map paste() simultaneously over all # elements of the objects at the second level. paste() is effectively # mapped at level 3. l1 %>% modify_depth(2, ~ pmap(., paste, sep = " / ")) %>% str()
#> List of 2 #> $ obj1:List of 2 #> ..$ prop1:List of 2 #> .. ..$ : chr "1 / 3" #> .. ..$ : chr "2 / 4" #> ..$ prop2:List of 2 #> .. ..$ : chr "5 / 7" #> .. ..$ : chr "6 / 8" #> $ obj2:List of 2 #> ..$ prop1:List of 2 #> .. ..$ : chr "9 / 11" #> .. ..$ : chr "10 / 12" #> ..$ prop2:List of 3 #> .. ..$ : chr "12 / 15" #> .. ..$ : chr "13 / 16" #> .. ..$ : chr "14 / 17"