Reputation: 19375
Consider this simple example:
mytib <- tibble(city_name1 = c('nyc', 'DC'),
planet_name1 = c('earth', 'moon'))
func_planet <- function(var){str_to_upper(var)}
func_city <- function(var){str_to_lower(var)}
mytib %>%
mutate(new_planet= map_chr(planet_name1, ~func_planet(.x)))
# A tibble: 2 x 3
city_name1 planet_name1 new_planet
<chr> <chr> <chr>
1 nyc earth EARTH
2 DC moon MOON
Easy enough. But now assume I want to loop over different prefixes (city
instead of planet
). Is it possible to automate this in the tidyverse
?
See the complication in the code below: we are creating a variable, calling a function and referencing a variable dynamically.
for(var in c('planet', 'city')){
mytib %>%
mutate(glue('new_{var}' := map(!!glue('{var}_name1', ~glue('func_{var}')(.x)))
}
Upvotes: 1
Views: 89
Reputation: 1843
Building up a bit on @tmfmnk 's answer, perhaps this is what you're looking for:
mytib <- tibble(city_name1 = c('nyc', 'DC'),
planet_name1 = c('earth', 'moon'))
func_planet <- function(var){str_to_upper(var)}
func_city <- function(var){str_to_lower(var)}
funcnames <- c("planet", "city")
map2(.x = funcnames,
.y = paste0("func_", funcnames),
~ mytib %>% mutate(across(.cols = starts_with(.x), .fns = as.list(.y), .names = "{col}_new"))) %>%
reduce(full_join)
# Joining, by = c("city_name1", "planet_name1")
# # A tibble: 2 x 4
# city_name1 planet_name1 planet_name1_new city_name1_new
# <chr> <chr> <chr> <chr>
# 1 nyc earth EARTH nyc
# 2 DC moon MOON dc
mytib1 <- tibble(city_name1 = c('nyc', 'DC'),
planet_name1 = c('earth', 'moon'),
fruit_name1 = c('SUNFLOWER', 'WALDO'))
func_planet <- function(var){str_to_upper(var)}
func_city <- function(var){str_to_lower(var)}
func_fruit <- function(var){str_count(var)}
funcnames <- c("planet", "city", "fruit")
map2(.x = funcnames,
.y = paste0("func_", funcnames),
~ mytib1 %>% mutate(across(.cols = starts_with(.x), .fns = as.list(.y), .names = "{col}_new"))) %>%
reduce(full_join)
# # A tibble: 2 x 6
# city_name1 planet_name1 fruit_name1 planet_name1_new city_name1_new fruit_name1_new
# <chr> <chr> <chr> <chr> <chr> <int>
# 1 nyc earth SUNFLOWER EARTH nyc 9
# 2 DC moon WALDO MOON dc 5
You should be able to loop over whatever function names you want to, as long as they have a corresponding prefix in a pre-existing column in the tibble
/data.frame
.
Upvotes: 1
Reputation: 39858
A different approach could be:
map2(.x = c("planet", "city"),
.y = c(func_planet, func_city),
~ mytib %>%
mutate(across(starts_with(.x), .y, .names = "{col}_new"))) %>%
reduce(full_join)
city_name1 planet_name1 planet_name1_new city_name1_new
<chr> <chr> <chr> <chr>
1 nyc earth EARTH nyc
2 DC moon MOON dc
Or if you want to glue the names in the vector:
map2(.x = c("planet", "city"),
.y = c(func_planet, func_city),
~ mytib %>%
mutate(across(starts_with(.x), .y, .names = glue("new_", {.x})))) %>%
reduce(full_join)
city_name1 planet_name1 new_planet new_city
<chr> <chr> <chr> <chr>
1 nyc earth EARTH nyc
2 DC moon MOON dc
Upvotes: 4
Reputation: 160417
Sopmething like this?
mytib %>%
# mutate(across(city_name1:planet_name1, list(new = function(z) map_chr(z, ~ func_planet(.x)))))
# # A tibble: 2 x 4
# city_name1 planet_name1 city_name1_new planet_name1_new
# <chr> <chr> <chr> <chr>
# 1 nyc earth NYC EARTH
# 2 DC moon DC MOON
across
will work with character
vectors as well, as in
mytib %>%
mutate(across(c("city_name1", "planet_name1"), list(new = function(z) map_chr(z, ~ func_planet(.x)))))
Upvotes: 1