TarJae
TarJae

Reputation: 79311

Mutate a new column and paste value from existing columns conditional on string in column names

I have this dataframe:

df <- structure(list(number = 1:3, a_1 = c(1L, 4L, 7L), a_2 = c(2L, 
5L, 8L), a_3 = c(3L, 6L, 9L)), class = "data.frame", row.names = c(NA, 
-3L))

  number a_1 a_2 a_3
1      1   1   2   3
2      2   4   5   6
3      3   7   8   9

I want to mutate a new_col and fill it with values conditional on string match of column number to column names.

Desired output:

  number   a_1   a_2   a_3 new_col
   <int> <int> <int> <int>   <int>
1      1     1     2     3       1
2      2     4     5     6       5
3      3     7     8     9       9

I tried with str_extract, str_detect ... but I can't do it!

Upvotes: 3

Views: 1196

Answers (3)

Martin Gal
Martin Gal

Reputation: 16998

Or using some pivot_*:

library(tidyr)
library(dplyr)

df %>% 
  pivot_longer(-number, names_pattern = "a_(\\d+)") %>% 
  group_by(number) %>% 
  mutate(new_col = value[name == number]) %>% 
  pivot_wider(names_from = name, names_prefix = "a_") %>% 
  ungroup()

returning

# A tibble: 3 x 5
  number new_col   a_1   a_2   a_3
   <int>   <int> <int> <int> <int>
1      1       1     1     2     3
2      2       5     4     5     6
3      3       9     7     8     9

Upvotes: 3

Anoushiravan R
Anoushiravan R

Reputation: 21938

Or maybe this one:

library(dplyr)

df %>%
  rowwise() %>%
  mutate(new_col = c_across(starts_with("a"))[grepl(number, names(df[-1]))])

# A tibble: 3 x 5
# Rowwise: 
  number   a_1   a_2   a_3 new_col
   <int> <int> <int> <int>   <int>
1      1     1     2     3       1
2      2     4     5     6       5
3      3     7     8     9       9

Upvotes: 2

akrun
akrun

Reputation: 887971

We may use get after pasteing the 'a_' with 'number'

library(dplyr)
library(stringr)
df %>% 
    rowwise %>%
    mutate(new_col = get(str_c('a_', number))) %>%
    ungroup

-output

# A tibble: 3 x 5
  number   a_1   a_2   a_3 new_col
   <int> <int> <int> <int>   <int>
1      1     1     2     3       1
2      2     4     5     6       5
3      3     7     8     9       9

It may be better to use a vectorized option with row/column indexing

df$newcol <- df[-1][cbind(seq_len(nrow(df)),
        match(paste0("a_", df$number), names(df)[-1]))]

Upvotes: 2

Related Questions