I know the use of for-loop in R is often unnecessary, because it supports vectorization. I want to program as efficient as possible, there for my question concerning the following example code.
I have a hexagonal grid, and I am calculating the number of the cell, this counts from 1 to 225 in my example starting in the left lower corner, going to the right. So cell 16 is placed a bit offset right above cell 1. see snapshot:
Therefor, if I have the Y coordinate, the X coordinate has to be either rounded, or ceiling. In my application the user points out cells, I save this and in a for loop go through the cells to determine the cells he chose as follows, with toy input values for Xcells and Ycells the user would have chosen:
gridsize <- 15
Xcells <-c(0.8066765, 1.8209879, 3.0526517, 0.5893240)
Ycells <-c(0.4577802, 0.4577802, 0.5302311, 1.5445425)
clicks <- length(Xcells)
cells <-vector('list', clicks)
This corresponds to cell 1 2 3 and 16. 4 clicks. Now to determine the cell numbers:
Y <- ceiling(Ycells)
for(i in 1:clicks){
if(Y[i]%%2==1){
X[i] <- round(Xcells[i])
}
else{
X[i]<- ceiling(Xcells[i])
}
#determine the cell numbers and store in predefined list
cells[[i]] <- (Y[i]-1)*gridsize + X[i]
}
So if the Y is 'even' the X has to be rounded, and if the Y is 'un-even' it has to be the ceiling value.
Is there a way to do this without the for loop, by using the vectorization?
You can vectorize this as follows
(Y - 1) * gridsize + ifelse(Y %% 2 == 1, round(Xcells), ceiling(Xcells))
# [1] 1 2 3 16
(I'm not sure pre-calculating round(Xcells)
and ceiling(Xcells)
will improve this a bit more - you could try)
Another option (if you want to avoid ifelse
) could be
(Y - 1) * gridsize + cbind(ceiling(Xcells), round(Xcells))[cbind(1:length(Xcells), Y %% 2 + 1)]
# [1] 1 2 3 16
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With