user5577796
user5577796

Reputation: 221

Object not found for lapply data.table within function

Suppose I have the following R code:

library(data.table)
L <- list(a=data.table(x=c(1,2,3),y=c(10,20,30)),
          b=data.table(x=c(4,5,6),y=c(40,50,60)),
          c=data.table(x=c(7,8,9),y=c(70,80,90)))


columnName <- "x"         
r <- lapply(L,"[",i=get(columnName) %in% c(1,4))

f <- function(L1) {
     columnName1 <- "x"
     r1 <- lapply(L1,"[",i=get(columnName1) %in% c(1,4))
     return(r1)
}

r1 <- f(L)

My question is: Why does the assignment to r1 at the bottom fail inside the function with

Error in get(columnName1) : object 'columnName1' not found

The assigment to r further up works fine. Likewise, if, inside the function I change it to a global assignment for columnName1 via <<-, but then I have created a global variable which I don't really want.... How can I cleanly rewrite this such that data.table finds columnName1 within its scope? And what am I missing about scoping? I would have thought that if it can't find columnName1 within the "[" function it will look one environment "up" and find it there? It must look in the global environment though, but not in the parent?

Upvotes: 8

Views: 3806

Answers (2)

akuiper
akuiper

Reputation: 214987

The lapply sugar syntax probably complicates things here, in which case the expression will be treated as arguments, which makes it harder to know which environment the expression is evaluated. Also the get() function has been probably modified when used with data.table() since the signature is different than normal use case. One work around here is to create your own anonymous function which guarantees that the get will be evaluated within [.data.table call.

f <- function(L1) {
     columnName1 <- "x"
     r1 <- lapply(L1, function(x) x[i=get(columnName1) %in% c(1,4)])
     r1
}

r1 <- f(L)

r1
#$a
#   x  y
#1: 1 10

#$b
#   x  y
#1: 4 40

#$c
#Empty data.table (0 rows) of 2 cols: x,y

Still not sure what causes the failure, probably some data.table experts can clarify here.

Upvotes: 0

manotheshark
manotheshark

Reputation: 4357

I'm guessing slight what you're looking to return from the data.table. If you're looking to return rows where column x equals 1 and 4 it's usually easier to get it to work with a single value from the list and then get it to work with lapply

library(data.table)
columnName1 <- "x"
L$a[get(columnName1) %in% c(1,4)]

to iterate through the list

lapply(L, function(x) x[get(columnName1) %in% c(1,4)])

if you want a function that can specify the column name and row numbers

f <- function(list, col, row) {lapply(list, function(x, lcol, lrow) x[get(lcol) %in% lrow], lcol=col, lrow=row)}
f(L, "x", c(1,4))

Upvotes: 1

Related Questions