Search code examples
rperformancerandomvectorindexing

Fill elements of a vector randomly depending on constraints


I have a character vector of a certain length (that should not be changed) like this:

my.vec <- rep("free", 40000) 

What I need to do now is the following:

  • I need to loop 22 through the vector to represent an annual development (1 loop = 1 year)
  • in each loop 7 random elements of the vector should be changed from "free" to "occupied"
  • between two "occupied" elements there are supposed to stay at least 4 "free" elements (i.e. "occupied" "free" "free" "free" "free" "occupied"
  • if an element gets assigned "occupied" in one loop, is not available anymore for the next loops

For more clarity, here is an example with a short vector and three time steps:

# this is the intital vector:
my.vec <- rep("free", 200) 

# this is the assignment in the first three time steps:
# first time step
my.vec[c(1,25,18,10,48,41,33)] <- "occupied"
# second time step
my.vec[c(98,91,81,63,70,163,120)] <- "occupied"
# third time step
my.vec[c(199,127,150,140,172)] <- "occupied"

I hope it became clear. Anybody with an idea how to implement this?


Solution

  • How about this:

    my.vec <- rep("free", 4000)  
    
    # Function to check if a position can be marked 'occupied'
    can_occupy <- function(vec, pos) {
      # Check boundaries and ensure at least four 'free' slots between 'occupied'
      if(pos < 1 || pos > length(vec)) {
        return(FALSE)
      }
      lower_bound <- max(1, pos - 4)
      upper_bound <- min(length(vec), pos + 4)
      # If any 'occupied' within bounds, return FALSE
      return(all(vec[lower_bound:upper_bound] == "free"))
    }
    
    for(year in 1:22) {
      occupied_this_year <- 0
      attempts <- 0  # To prevent infinite loop in case conditions can't be met
      while(occupied_this_year < 7 && attempts < 1000) {
        # Randomly select a position
        pos <- sample(length(my.vec), 1)
        if(can_occupy(my.vec, pos)) {
          my.vec[pos] <- "occupied"
          occupied_this_year <- occupied_this_year + 1
        }
        attempts <- attempts + 1
      }
      if(attempts == 1000) {
        cat("Year", year, ": Could not occupy 7 positions\n")
      }
    }