3
votes

I have function that operates on words using data.table which assigns a list of vectors as a column. This works well unless the data.table is one row. I demonstrate this problem below. How can I make data.table assign the list of one vector as a column in the same way I had it ad a list of 2 vectors as a column?

MWE

dat2 <- dat <- data.frame(
    x = 1:2,
    y = c('dog', 'cats'), 
    stringsAsFactors = FALSE
)

library(data.table)
setDT(dat)           # 2 row data.table
(dat2 <- dat2[1, ])  # single row data.frame
setDT(dat2)

letterfy <- function(x) strsplit(x, "") 

## works as expected when >= 2 rows
dat[, letters := letterfy(y)]
dat

##    x    y letters
## 1: 1  dog   d,o,g
## 2: 2 cats c,a,t,s

## Try on 1 row
dat2[, letters := letterfy(y)]

#Warning message:
#In `[.data.table`(dat2, , `:=`(letters, letterfy(y))) :
#  Supplied 3 items to be assigned to 1 items of column 'letters' (2 unused)

#   x   y letters
#1: 1 dog       d

Desired Output for dat2

##    x    y letters
## 1: 1  dog   d,o,g
1

1 Answers

5
votes

Simply wrap the output in list:

> dat2[, letters := list(letterfy(y))][ ]
   x   y letters
1: 1 dog   d,o,g

Note that dat[ , class(letters)] is list; since typically lists are passed on the RHS of := for multiple assignments, it seems data.table was a bit confused. I imagine the developers have a reason for unlisting in the assignment here... but this approach also works when there is more than one row, i.e., dat[ , letters := list(letterfy(y))] also works as expected.

Another option is to assign the letters column as a character vector by changing letterfy:

letterfy2 <- function(x) lapply(strsplit(x, ""), paste0, collapse = ",")
> dat[ , letters := letterfy2(y)][ ]
   x    y letters
1: 1  dog   d,o,g
2: 2 cats c,a,t,s
dat2[, letters := letterfy2(y)][ ]
   x   y letters
1: 1 dog   d,o,g