0

This is related to this question from Henrik Assign multiple columns using := in data.table, by group

But what if I want to create a new data.table with given column names instead of assigning new columns to an existing one?

f <- function(x){list(head(x,2),tail(x,2))}
dt <- data.table(group=sample(c('a','b'),10,replace = TRUE),val=1:10)

> dt
    group val
 1:     b   1
 2:     b   2
 3:     a   3
 4:     b   4
 5:     a   5
 6:     b   6
 7:     a   7
 8:     a   8
 9:     b   9
10:     b  10

I want to get a new data.table with predefined column names by calling the function f:

dt[,c('head','tail')=f(val),by=group]

I wish to get this:

   group head tail
1:     a    1    8
2:     a    3   10
3:     b    2    6
4:     b    5    9

But it gives me an error. What I can do is create the table then change the column names, but that seems cumbersome:

> dt2 <- dt[,f(val),by=group]

> dt2
   group V1 V2
1:     a  1  8
2:     a  3 10
3:     b  2  6
4:     b  5  9

> colnames(dt2)[-1] <- c('head','tail')

> dt2
   group head tail
1:     a    1    8
2:     a    3   10
3:     b    2    6
4:     b    5    9

Is it something I can do with one call?

Dason
  • 60,663
  • 9
  • 131
  • 148
Bill
  • 55
  • 2
  • 7
  • 1
    Why don't you just define `f` with the names in it? `f <- function(x){list(head = head(x,2), tail = tail(x,2))}`? Or, I guess `dt[, setNames(f(val), c("head", "tail")), group]` should work. – A5C1D2H2I1M1N2O1R2T1 Aug 09 '17 at 17:21
  • @A5C1D2H2I1M1N2O1R2T1 Downside to the second way is that data.table complains (albeit only quietly, when `verbose = TRUE`). I guess the real issue is that when using data.table programmatically (at least in ways as general as the OP wants), it's best to construct expressions or full `[.data.table` calls to evaluate... – Frank Aug 09 '17 at 17:33
  • @A5C1D2H2I1M1N2O1R2T1 As Frank said, the names in the data table will be determined programmatically so I cannot hard-code it in the function. But your second way does work. Thanks. – Bill Aug 09 '17 at 19:32
  • @Frank by 'it's best to construct expressions', do you mean to have an inline function instead of calling an existing one? – Bill Aug 09 '17 at 19:33
  • I mean something like https://github.com/franknarf1/r-tutorial/issues/11 It gets pretty messy, so I rarely build tables + functions where I'll need to determine input or output column names dynamically. Here's another example: https://stackoverflow.com/questions/37007282/r-data-table-join-sql-select-alike-syntax-in-joined-tables and more generally https://www.google.com/search?biw=1024&bih=1137&q=%22as.call%22+data.table+site%3Astackoverflow.com – Frank Aug 09 '17 at 19:42

1 Answers1

0

From running your code as-is, this is the error I get:

dt[,c('head','tail')=f(val),by=group]
# Error: unexpected '=' in "dt2[,c('head','tail')="

The problem is using = instead of := for assignment.

On to your problem of wanting a new data.table:

dt2 <- dt[, setNames(f(val), c('head', 'tail')), by = group]
Nathan Werth
  • 5,093
  • 18
  • 25
  • Thanks, this works. Although @A5C1D2H2I1M1N2O1R2T1 gave this solution earlier in the comment. Still accepting your answer. – Bill Aug 09 '17 at 19:35