Reputation: 13503
I must admit that the data.table
j
syntax confuses me.
I am attempting to use list()
to extract a subset of a data.table
as a data.table
object as described in Section 1.4 of the data.table FAQ, but I can't get this behavior to work inside of a function.
An example:
require(data.table)
## Setup some test data
set.seed(1)
test.data <- data.table( X = rnorm(10),
Y = rnorm(10),
Z = rnorm(10) )
setkey(test.data, X)
## Notice that I can subset the data table easily with literal names
test.data[, list(X,Y)]
## X Y
## 1: -0.8356286 -0.62124058
## 2: -0.8204684 -0.04493361
## 3: -0.6264538 1.51178117
## 4: -0.3053884 0.59390132
## 5: 0.1836433 0.38984324
## 6: 0.3295078 1.12493092
## 7: 0.4874291 -0.01619026
## 8: 0.5757814 0.82122120
## 9: 0.7383247 0.94383621
## 10: 1.5952808 -2.21469989
I can even write a function that will return a column of the data.table
as a vector when passed the name of a column as a character vector:
get.a.vector <- function( my.dt, my.column ) {
## Step 1: Convert my.column to an expression
column.exp <- parse(text=my.column)
## Step 2: Return the vector
return( my.dt[, eval(column.exp)] )
}
get.a.vector( test.data, 'X')
## [1] -0.8356286 -0.8204684 -0.6264538 -0.3053884 0.1836433 0.3295078
## [7] 0.4874291 0.5757814 0.7383247 1.5952808
But I cannot pull a similar trick for list()
. The inline comments are the output from the interactive browser()
session.
get.a.dt <- function( my.dt, my.column ) {
## Step 1: Convert my.column to an expression
column.exp <- parse(text=my.column)
## Step 2: Enter the browser to play around
browser()
## Step 3: Verity that a literal X works:
my.dt[, list(X)]
## << not shown >>
## Step 4: Attempt to evaluate the parsed experssion
my.dt[, list( eval(column.exp)]
## Error in `rownames<-`(`*tmp*`, value = paste(format(rn, right = TRUE), (from data.table.example.R@1032mCJ#7) :
## length of 'dimnames' [1] not equal to array extent
return( my.dt[, list(eval(column.exp))] )
}
get.a.dt( test.data, "X" )
What am I missing?
Update:
Due to some confusion as to why I would want to do this I wanted to clarify. My use case is when I need to access a data.table column when when I generate the name. Something like this:
set.seed(2)
test.data[, X.1 := rnorm(10)]
which.column <- 'X'
new.column <- paste(which.column, '.1', sep="")
get.a.dt( test.data, new.column )
Hopefully that helps.
Upvotes: 0
Views: 1946
Reputation: 49448
It sounds like you simply want:
dt = data.table(a = 1:5, b = 2:6, c = 3:7)
var = "a"
dt[, var, with = FALSE]
# a
#1: 1
#2: 2
#3: 3
#4: 4
#5: 5
But just for fun, here's a universal retriever function, that you can give either variable names or variables:
retrieve = function(dt, ...) {
vars = as.character(substitute(list(...))[-1])
dt[, vars, with = FALSE]
}
retrieve(dt, a)
# a
#1: 1
#2: 2
#3: 3
#4: 4
#5: 5
retrieve(dt, b, "c")
# b c
#1: 2 3
#2: 3 4
#3: 4 5
#4: 5 6
#5: 6 7
Upvotes: 5
Reputation: 17432
eval
goes to parent.frame()
environment. If you really want to use this method for getting a column (why?????), use get
:
get.a.dt <- function( my.dt, my.column ) {
return( my.dt[, list(get(my.column))] )
}
get.a.dt( test.data, "X" )
Upvotes: 0