If we look at how modify_depth
is implemented, it is really not very fancy and basically performs modification at a fixed level. The .ragged
parameter handles lists with heterogeneous levels as @rensa suggested.
If we really want to use modify_depth
we have to iterate through each level:
library(purrr)
x <- list(list(a = as.character(1), b = as.double(2)),
c = as.character(3),
d = as.double(4))
as_integer_recursive <- function(x){
if (is.character(x)) {
as.integer(x)
} else if (length(x) > 1) {
map(x, as_integer_recursive)
} else {
x
}
}
x %>% as_integer_recursive() %>% str()
#> List of 3
#> $ :List of 2
#> ..$ a: int 1
#> ..$ b: num 2
#> $ c: int 3
#> $ d: num 4
as_integer_recursive_map <- function(x) {
x %>%
map_if(is.character, as.integer) %>%
map_if(is.list, as_integer_recursive_map)
}
x %>% as_integer_recursive_map() %>% str()
#> List of 3
#> $ :List of 2
#> ..$ a: int 1
#> ..$ b: num 2
#> $ c: int 3
#> $ d: num 4
as_integer_modify_depth <- function(x) {
reduce(
-seq(vec_depth(x) - 1),
function(x, depth) {
modify_depth(x, depth, ~if(is.character(.x)) as.integer(.x) else .x, .ragged = TRUE)
},
.init = x
)
}
x %>% as_integer_modify_depth() %>% str()
#> List of 3
#> $ :List of 2
#> ..$ a: int 1
#> ..$ b: num 2
#> $ c: int 3
#> $ d: num 4
microbenchmark::microbenchmark(
as_integer_recursive(x),
as_integer_recursive_map(x),
as_integer_modify_depth(x),
times = 100
)
#> Unit: microseconds
#> expr min lq mean median
#> as_integer_recursive(x) 31.026 35.6635 59.97857 40.9725
#> as_integer_recursive_map(x) 1898.626 2091.3115 3539.13028 2688.1005
#> as_integer_modify_depth(x) 386.974 422.1990 694.83505 470.1635
#> uq max neval
#> 65.128 277.072 100
#> 3976.983 11519.629 100
#> 681.178 3770.032 100
Created on 2018-10-18 by the reprex package (v0.2.1)