I want to sample integers in R, but also set constraints that for example, "3 comes always before 2" and "8 comes always before 5".
EDIT: The integers need not to be next to each other, for example, c(x,3,y,2,z) and c(8,x,y,z,5) are both acceptable, given these constraints.
Without any constraints one could just write:
sample(1:10)
...and that's it, but now we need something more. I like to think with tables or matrices so describing the relations with a matrix was my solution to this problem i.e.
# Create constraint matrix
constraint_matrix <- matrix(0, nrow = 10, ncol = 10)
# Set constraints
constraint_matrix[3, 2] <- 1 # 3 comes before 2
constraint_matrix[8, 5] <- 1 # 8 comes before 5
# Check, if generated output satisfies set constraints
check_constraints <- function(numbers, constraint_matrix) {
for (i in 1:(length(numbers) - 1)) {
if (constraint_matrix[numbers[i+1], numbers[i]] == 1) {
return(FALSE) # A constraint NOT satisfied
}
}
return(TRUE) # All constraints are satisfied
}
# Generate random order and check if constraints are satisfies
set.seed(123)
numbers <- sample(1:10)
while (!check_constraints(numbers, contstraint_matrix)) {
numbers <- sample(1:10)
}
print(numbers)
My question is whether there is a better, optimized function to do this? Or does someone know a better algorithm for this task?
Check if the order follows constraints, if not then just swap their positions:
set.seed(1); x <- sample(1:10)
x
# [1] 9 4 7 1 2 5 3 10 6 8
#"3 comes always before 2" and "8 comes always before 5".
cons <- list(c(3, 2), c(8, 5))
for(i in seq_along(cons)){
ix <- match(cons[[ i ]], x)
if(ix[ 1 ] > ix[ 2 ]) x[ rev(ix) ] <- cons[[ i ]]
}
x
# [1] 9 4 7 1 3 8 2 10 6 5