4

I'm looking to add a column to a data.table which is a concatenation of several other columns, the names of which I've stored in a vector cols. Per https://stackoverflow.com/a/21682545/1840471 I tried do.call + paste but couldn't get it working. Here's what I've tried:

# Using mtcars as example, e.g. first record should be "110 21 6"
dt <- data.table(mtcars)
cols <- c("hp", "mpg", "cyl")
# Works old-fashioned way
dt[, slice.verify := paste(hp, mpg, cyl)]
# Raw do.call+paste fails with message:
# Error in do.call(paste, cols): second argument must be a list
dt[, slice := do.call(paste, cols)]
# Making cols a list makes the column "hpmpgcyl" for each row
dt[, slice := do.call(paste, as.list(cols))]
# Applying get fails with message:
# Error in (function (x) : unused arguments ("mpg", "cyl")
dt[, slice := do.call(function(x) paste(get(x)), as.list(cols))]

Help appreciated - thanks.

Similar questions:

Community
  • 1
  • 1
Max Ghenis
  • 14,783
  • 16
  • 84
  • 132

2 Answers2

10

We can use mget to return the values of elements in 'cols' as a list

dt[, slice := do.call(paste, mget(cols))]
head(dt, 2)
#   mpg cyl disp  hp drat    wt  qsec vs am gear carb    slice
#1:  21   6  160 110  3.9 2.620 16.46  0  1    4    4 110 21 6
#2:  21   6  160 110  3.9 2.875 17.02  0  1    4    4 110 21 6

Or another option is to specify the 'cols' in .SDcols and paste the .SD

dt[, slice:= do.call(paste, .SD), .SDcols = cols]
head(dt, 2)
#   mpg cyl disp  hp drat    wt  qsec vs am gear carb    slice
#1:  21   6  160 110  3.9 2.620 16.46  0  1    4    4 110 21 6
#2:  21   6  160 110  3.9 2.875 17.02  0  1    4    4 110 21 6
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Thanks, I haven't seen `mget` before and don't see it in the references. How does this work differently from `get`? – Max Ghenis Jul 01 '16 at 06:49
  • 1
    @MaxGhenis @MaxGhenis It is similar to using `get` in a loop (for vectors that have length >1) `dt[, slice := do.call(paste, lapply(cols, function(x) get(x)))]` – akrun Jul 01 '16 at 06:59
  • 2
    `.SDcols` is the idiomatic way- just to make it clear. `mget`/`get` could get slow in different situations. – David Arenburg Jul 01 '16 at 07:22
1

Came across a possibly more simple solution using apply as follows:

df[, "combned_column"] <- apply(df[, cols], 1, paste0, collapse = "")

May not work for data.tables, but it did what I needed and possibly what was needed here.

giraffehere
  • 1,118
  • 7
  • 18