Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most idiomatic way to mutate multiple similar columns?

Tags:

r

dplyr

tidyr

I'm generating multiple columns in a mutate() call, all by using a function of 1) an already-existing column and 2) some value which is different for each output column. The following code produces what I want, but it smells:

df <- tibble(base_string = c("a", "b", "c"))
df_desired_result <- df |>
  mutate(
    one = str_c(base_string, "1"),
    two = str_c(base_string, "2"),
    three = str_c(base_string, "3")
  )
df_desired_result
# A tibble: 3 × 4
  base_string one   two   three
  <chr>       <chr> <chr> <chr>
1 a           a1    a2    a3   
2 b           b1    b2    b3   
3 c           c1    c2    c3   

If there were many other columns, this would be a bad solution.

The best improvement I've come up with is:

df_also_desired_result <- df |>
  expand_grid(
    tibble(
      number_name = c("one", "two", "three"),
      number_string = c("1", "2", "3")
    )
  ) |>
  mutate(final_string = str_c(base_string, number_string)) |>
  pivot_wider(
    id_cols = base_string,
    names_from = number_name,
    values_from = final_string
  )
df_also_desired_result
# A tibble: 3 × 4
  base_string one   two   three
  <chr>       <chr> <chr> <chr>
1 a           a1    a2    a3   
2 b           b1    b2    b3   
3 c           c1    c2    c3   

But this seems too verbose. Would love any suggestions on a nicer way to do this.

like image 264
eithompson Avatar asked Oct 18 '25 14:10

eithompson


1 Answers

Base R solution:

vars <- c("one"=1, "two"=2, "three"=3)
df <- data.frame(base_string = c("a", "b", "c"))

df[names(vars)] <- sapply(vars, \(x) paste0(df$base_string, x))
df

  base_string one two three
1           a  a1  a2    a3
2           b  b1  b2    b3
3           c  c1  c2    c3

If your variables and values are in separate vectors, as in your attempted solution, then use this variation:

vars = c("one", "two", "three")
vals = c("1", "2", "3")

df <- data.frame(base_string = c("a", "b", "c"))

df[vars] <- sapply(vals, \(x) paste0(df$base_string, x))
like image 156
Edward Avatar answered Oct 21 '25 02:10

Edward