Piet93 - 1 year ago 51

R Question

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?

Answer Source

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
```