Home > front end >  fill a column with name and content of 3 other columns
fill a column with name and content of 3 other columns

Time:10-07

dput(df)
structure(list(trtmt = c(26, 28, 35, 42, 49, 63, 33, 24, 38, 
4, 24, 10, 59, 20, 16, 15, 66, 23, 51, 41, 39, 17, 8, 9, 28, 
2, 13, 32, 43, 58, 4, 49, 63, 27, 27, 34, 6, 8, 57, 43, 23, 10, 
50, 47, 41, 65, 57, 21, 15, 35), R = c(150, 150, 0, 0, 25, 25, 
0, 100, 0, 150, 100, 0, 100, 50, 25, 25, 33, 100, 100, 0, 0, 
50, 0, 0, 150, 50, 25, 0, 0, 50, 150, 25, 25, 150, 150, 0, 0, 
0, 25, 0, 100, 0, 50, 100, 0, 100, 25, 100, 25, 0), V = c(50, 
150, 50, 150, 0, 100, 50, 150, 100, 0, 150, 0, 0, 150, 150, 100, 
30.3, 100, 0, 150, 100, 25, 150, 0, 150, 0, 25, 25, 150, 0, 0, 
0, 100, 100, 100, 50, 50, 150, 0, 150, 100, 0, 0, 0, 150, 25, 
0, 25, 100, 50), B = c(0, 0, 100, 50, 50, 25, 25, 0, 50, 0, 0, 
50, 150, 0, 0, 0, 1.8, 0, 50, 25, 100, 0, 0, 25, 0, 0, 0, 150, 
100, 150, 0, 50, 25, 0, 0, 50, 0, 0, 150, 100, 0, 50, 50, 25, 
25, 25, 150, 0, 0, 100)), row.names = c(NA, -50L), class = c("tbl_df", 
"tbl", "data.frame"))

    head(df)
# A tibble: 6 × 4
  trtmt     R     V     B
  <dbl> <dbl> <dbl> <dbl>
1    26   150    50     0
2    28   150   150     0
3    35     0    50   100
4    42     0   150    50
5    49    25     0    50
6    63    25   100    25

With the code below, I was telling R, for each row in the key column, grab the column names and values of R, V, and B, from left to right, and combine.

df %>%
rowwise() %>%
  mutate(key = paste0(names(.[2:4])[c_across() == c(2:4)], collapse = '_'))

but I got this error

Error in `mutate()`:
! Problem while computing `key = paste0(names(.)[c_across() == c(2:4)], collapse = "_")`.
ℹ The error occurred in row 1.
Caused by error:
! Can't combine `trtmt` <double> and `id` <character>.

What I expected is

  trtmt     R     V     B key            
  <dbl> <dbl> <dbl> <dbl> <chr>          
1    26   150    50     0 R150_V50_B0
2    28   150   150     0 R150_V150_B0
3    35     0    50   100 R0_V50_B100
4    42     0   150    50 R0_V150_B_50
5    49    25     0    50 R25_V0_B50
6    63    25   100    25 R25_V100_B25

I got the hint from Create new column containing names of other columns based on values ​of those columns.

Thanks for stopping by.

CodePudding user response:

We could use cur_column() to get the column names by looping across the columns of interest, paste (str_c) the column names with the values of the column, then use invoke (or exec from purrr - similar to do.call/Reduce in base R to paste the columns row wise)

library(purrr)
library(dplyr)
library(stringr)
df %>% 
   mutate( key = invoke(str_c, 
       across(R:B, ~ str_c(cur_column(), .x)),  sep = "_"))

-output

# A tibble: 50 × 5
   trtmt     R     V     B key         
   <dbl> <dbl> <dbl> <dbl> <chr>       
 1    26   150    50     0 R150_V50_B0 
 2    28   150   150     0 R150_V150_B0
 3    35     0    50   100 R0_V50_B100 
 4    42     0   150    50 R0_V150_B50 
 5    49    25     0    50 R25_V0_B50  
 6    63    25   100    25 R25_V100_B25
 7    33     0    50    25 R0_V50_B25  
 8    24   100   150     0 R100_V150_B0
 9    38     0   100    50 R0_V100_B50 
10     4   150     0     0 R150_V0_B0  
# … with 40 more rows

CodePudding user response:

Another way to do this is with sprintf(), my favorite little string function:

library(tidyverse)
df %>% mutate(key = sprintf('R%g_V%g_B%g',R ,V ,B ))

Note that unlike @akrun's solution this doesn't work if you need to dynamically assign the column names (i.e. if R V B are not known or can change).

# A tibble: 50 x 5
   trtmt     R     V     B key         
   <dbl> <dbl> <dbl> <dbl> <chr>       
 1    26   150    50     0 R150_V50_B0 
 2    28   150   150     0 R150_V150_B0
 3    35     0    50   100 R0_V50_B100 
 4    42     0   150    50 R0_V150_B50 
 5    49    25     0    50 R25_V0_B50  
 6    63    25   100    25 R25_V100_B25
 7    33     0    50    25 R0_V50_B25  
 8    24   100   150     0 R100_V150_B0
 9    38     0   100    50 R0_V100_B50 
10     4   150     0     0 R150_V0_B0 
  • Related