rdata.table

Add each element of a vector as new column in data.table


If a vector has 5 elements, I need to add 5 columns to my data.table. My first new column has for unique value the element 1 of my vector.

This is something I can do with a for, as in my reprex below :

foo <- data.table(col1 = 1:10, col2 = sample(letters[1:5], replace = TRUE))

fun.add <- function(DT) {
  
  v1 <- c(3, 5.5, 9)
  v2 <- c("x", "y", "z")
  
  for (j in 1:3) {
    DT[, paste0("aaa", j) := v1[j]]
    DT[, paste0("bbb", j) := v2[j]]
  }
  
  # DT[, paste0("aaa", 1:3),  := ...]
}

fun.add(foo)

I would prefer to do it without the for and rather like in the comment line. In this case, I can't use lapply and .SD ... Is there a way to ? Another way ?

Thanks !!


Solution

  • We could do this more efficiently instead of doing this in a for loop i.e. convert the vectors to a list with as.list and create the columns by assignment (:=) to the vector of column names created with paste (paste is vectorized)

    foo[, paste0("aaa", seq_along(v1)) := as.list(v1)]
    foo[, paste0("bbb", seq_along(v2)) := as.list(v2)]
    

    If we wrap it in a function

    fun.add <- function(DT) {
         v1 <- c(3, 5.5, 9)
         v2 <- c("x", "y", "z")
         DT[, paste0("aaa", seq_along(v1)) := as.list(v1)]
         DT[, paste0("bbb", seq_along(v2)) := as.list(v2)][]
        return(DT)
    }
    

    -testing

    > fun.add(foo)
        col1 col2 aaa1 aaa2 aaa3 bbb1 bbb2 bbb3
     1:    1    a    3  5.5    9    x    y    z
     2:    2    e    3  5.5    9    x    y    z
     3:    3    d    3  5.5    9    x    y    z
     4:    4    c    3  5.5    9    x    y    z
     5:    5    b    3  5.5    9    x    y    z
     6:    6    a    3  5.5    9    x    y    z
     7:    7    e    3  5.5    9    x    y    z
     8:    8    d    3  5.5    9    x    y    z
     9:    9    c    3  5.5    9    x    y    z
    10:   10    b    3  5.5    9    x    y    z