First, let's look at how the setkey
function does things from the data.table
package:
# setkey function
function (x, ..., verbose = getOption("datatable.verbose"))
{
if (is.character(x))
stop("x may no longer be the character name of the data.table. The possibility was undocumented and has been removed.")
cols = getdots()
if (!length(cols))
cols = colnames(x)
else if (identical(cols, "NULL"))
cols = NULL
setkeyv(x, cols, verbose = verbose)
}
So, when you do:
require(data.table)
dt <- data.table(ID=c(1,1,2,2,3), y = 1:5)
setkey(dt, ID)
It calls the function getdots
which is internal to data.table
(that is, it's not exported). Let's have a look at that function:
# data.table:::getdots
function ()
{
as.character(match.call(sys.function(-1), call = sys.call(-1),
expand.dots = FALSE)$...)
}
So, what does this do? It takes the parameter you entered in setkey
and it uses match.call
to extract the arguments separately. That is, the match.call
argument for this example case would be:
setkey(x = dt, ... = list(ID))
and since it's a list, you can access the ...
parameter with $...
to get a list of 1 element with its value ID
and converting to this list to a character with as.character
results in "ID"
(a character vector). And then setkey
passes this to setkeyv
internally to set the keys.
Now why doesn't this work when you write setkey(table, key)
inside your function?
This is precisely because of the way setkey/getdots
is. The setkey
function is designed to take any argument after the first argument (which is a data.table
) and then return the ...
argument as a character.
That is, if you give setkey(dt, key)
then it'll return cols <- "key"
. If you give setkey(dt, e)
, it'll give back cols <- "e"
. It doesn't look for if "key" is an existing variable and then if so substitute the value of the variable. All it does is convert the value you provide (whether it be a symbol or character) back to a character.
Of course this won't work in your case because you want the value in key
= ID to be provided in setkey
. At least I can't think of a way to do this.
How to get around this?
As @agstudy already mentions, the best/easiest way is to pass "ID"
and use setkeyv
. But, if you really insist on using f("table.csv", ID)
then, this is what you could do:
f <- function(path, key) {
table = data.table(read.delim(path, header=TRUE))
e = as.character(match.call(f)$key)
setkeyv(table, e)
return(table)
}
Here, you first use match.call
to get the value corresponding to argument key
and then convert it to a character
and then pass that to setkeyv
.
In short, setkey
internally uses setkeyv
. And imho, setkey is a convenient function to be used when you already know the column name of the data.table
for which you need to set the key. Hope this helps.
data.table
is not a function. – Ellersicksetkeyv
here and give the ID as a character? – Garnetdata.table
package. Just made the edit and added the tag. – Hilariahilario