A possible duplicate is here but it does not help me. My case is different perhaps.
Consider a sample data.table.
set.seed(21)
DT <- data.table(col1=sample(x=1:10,size = 5),col2=sample(x=10:20,size=5))
DT
col1 col2
1: 8 20
2: 3 11
3: 6 19
4: 2 17
5: 10 15
And consider a function check
I want to apply to each row:
check <- function(x,y) if ((y-x)>10) "A" else "B"
Now if I run this assignment by reference calling the function check
in the j
section of DT
, it fails miserably,
DT[,state:=check(col1,col2)]
And throws this warning
Warning message:
In if ((y - x) > 10) "A" else "B" :
the condition has length > 1 and only the first element will be used
Obviously, I guessed that data.table processes the whole vector at once and the function needs one value so I thought the last value is the current value in the vector so I made this change, which seems another stupid move :-)
DT[,state:=check(last(col1),last(col2))]
DT
col1 col2 state
1: 8 20 B
2: 3 11 B
3: 6 19 B
4: 2 17 B
5: 10 15 B
I see the check()
function was computed for the last value and overwrote all previous values every time. What I want is this output:
DT
col1 col2 state
1: 8 20 A
2: 3 11 A
3: 6 19 A
4: 2 17 A
5: 10 15 B
So how do I make a function call work in a data.table for each row independently?
ACTUAL FUNCTION:
After I received a suggestion from akrun to use ifelse
, which works fine for a simple condition like check()
but I have a slightly more complicated function here. So please replace check
by allowed_state
allowed_state <- function(old=NULL,new=NULL){
legalst<-data.table(from=c(1,1,9,9,7,8,7,10,10,11,11,10,11,8,7),to=c(11,7,10,7,8,7,9,9,7,1,7,1,7,9,10)) # all legal state transitions for a user
if(new %in% legalst[from==old,to]) "Legal" else "Illegal state change"
}