逐行连接 data.table 中各列的名称和值

concatenate names and values across columns in data.table, row by row

问题类似,我想连接列值的子集。但是,我还想在每个值前面加上列名,用“:”分隔名称和值,并控制用于分隔 name/value 对的字符。

例如,这给出了值的串联:

library(data.table)
d <- data.table(x = c(1, 2), y = c(3, 4))

labs_to_get <- c("x", "y")


d[
  ,
  .(x, y, labs = do.call(paste, c(.SD, sep = ", "))),
  .SDcols = labs_to_get
]
#>    x y labs
#> 1: 1 3 1, 3
#> 2: 2 4 2, 4

但我正在寻找这个:

d[
  ,
  .(x, y, labs = c("x: 1, y: 3", "x: 2, y: 4"))
]
#>    x y       labs
#> 1: 1 3 x: 1, y: 3
#> 2: 2 4 x: 2, y: 4

reprex package (v2.0.1)

于 2022-04-01 创建

我们可以paste对应的名字Map

d[,
  .(x, y, labs = do.call(paste, c(Map(function(u, v) 
       paste0(v, ": ", u), .SD, labs_to_get), sep = ", "))),
  .SDcols = labs_to_get
]

-输出

     x     y       labs
   <num> <num>     <char>
1:     1     3 x: 1, y: 3
2:     2     4 x: 2, y: 4

或者另一个选项是 write.dcf

d[, labs := do.call(paste, 
        c(as.list(setdiff(capture.output(write.dcf(.SD)), "")), 
     sep = ", ")), 1:nrow(d)]
> d
       x     y       labs
   <num> <num>     <char>
1:     1     3 x: 1, y: 3
2:     2     4 x: 2, y: 4

或使用apply遍历行

d[, labs := apply(.SD, 1, \(x) paste(names(x), x, sep = ": ", 
    collapse = ", ")), .SDcols = labs_to_get]

或使用tidyverse

library(dplyr)
library(purrr)
library(stringr)
d %>% 
  mutate(labs = invoke(str_c, c(across(all_of(labs_to_get),  
      ~str_c(cur_column(), ": ", .x)), sep = ", ")))
       x     y       labs
   <num> <num>     <char>
1:     1     3 x: 1, y: 3
2:     2     4 x: 2, y: 4

这是另一种 tidyverse 方法:

library(dplyr)
library(tidyr)

labs_to_get <- c("x", "y")

d %>% 
  mutate(across(everything(), ~case_when(cur_column() %in% labs_to_get ~ paste(cur_column(), ., sep = ": "))
                , .names = 'new_{col}')) %>%
  unite(labs, starts_with('new'), na.rm = TRUE, sep = ', ')
   x y       labs
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4

怎么样:

d[,labs:=paste0(labs_to_get,":",c(.SD), collapse=", "), by=1:nrow(d), .SDcols=labs_to_get]

输出:

       x     y     labs
   <num> <num>   <char>
1:     1     3 x:1, y:3
2:     2     4 x:2, y:4