Home > Software engineering >  Part 2: How to make nested for-loop do every permutation
Part 2: How to make nested for-loop do every permutation

Time:09-27

This is an update to the first question I asked. I essentially am still missing the pretty obvious learning lesson and can't expand the code that worked originally.

Trying to store a nested loop that runs all permutations of calculations.

I'm missing understanding on how to set up the index still. I am now trying to set this up with three sets of loops (and really, I want to set this up so I understand how to do it with any # of them). The code below doesn't exactly work, the third loop doesn’t index over every combination (but I get 1000 calculations anyway) I commented the part that is clearly wrong...

With only two loops, this was sufficient, per the answer of my first post:

index <- 10*(i-1)   j

So not sure why the way I changed it for 3 loops doesn't work, but it's obviously wrong.

iter = 10  #length of parameter ranges to test
perm = 3   #how many parameters are being varied

n_c <- 1 
m_c <- 1
n_n <- 1
m_n <- 1
n_v <- 1

my_data_c <- vector("numeric", iter^perm) 
my_data_n <- vector("numeric", iter^perm)
my_data_v <- vector("numeric", iter^perm)

rho_c_store <- vector("numeric", iter)
rho_n_store <- vector("numeric", iter)
rho_v_store <- vector("numeric", iter)

for (i in 1:iter) {
  # you can move this assignment to the outer loop
  rho_c <- (i / 10)
  x <- (rho_c * n_c)/m_c
  
  for (j in 1:iter) {
    rho_n <- (j / 10)
    y <- (rho_n * n_n)/m_n
    for (k in 1:iter){
      rho_v <- (k / 10)
      z <- rho_v/n_v
      
      index <- iter*(i-2) j  k            #Clearly where the error is
      rho_c_store[index] <- rho_c
      rho_n_store[index] <- rho_n
      rho_v_store[index] <- rho_v
      
      my_data_c[index] <- x
      my_data_n[index] <- y
      my_data_v[index] <- z
    }
  }
}

my_data <- cbind(rho_c_store, rho_n_store, rho_v_store, my_data_c, my_data_n,my_data_v)

print(my_data)

CodePudding user response:

Think of it as if you were counting: the ones move the fastest, next come the tens, then the hundredes. 001, 002, ..., 010, ..., 099, 100, 101. You can think of your loop variables ijk like the digits of a number - k moves the fastest, j slower and i slower still. To get the right index you have to multiply the i with 100, the j with 10 and the k with one, givin you the index 100 * (i-1) 10 * (j-1) k. The -1 for i and j is necessary because the loop variable starts from 1, but we want to start by adding 0 * 100 and 0 * 10.

So all you need to do is change your index calculation to index <- iter^2*(i-1) iter*(j-1) k.

# I stripped the example to the essentials for easier understanding
iter = 10  #length of parameter ranges to test
perm = 3   #how many parameters are being varied

my_data_c <- vector("numeric", iter^perm) 
my_data_n <- vector("numeric", iter^perm)
my_data_v <- vector("numeric", iter^perm)

for (i in 1:iter) {
  x <- i / 10
  
  for (j in 1:iter) {
    y <- j / 10
    
    for (k in 1:iter){
      z <- k / 10
      
      index <- iter^2*(i-1)  iter*(j-1)   k
      
      my_data_c[index] <- x
      my_data_n[index] <- y
      my_data_v[index] <- z
    }
  }
}

my_data <- cbind(my_data_c, my_data_n, my_data_v)

print(my_data)

Anyway, while it's great to develop an deep understanding of these things you're certainly on the right track when you move away from looping with explicit indices and use R's toolkit for such tasks.

Hope this helps

CodePudding user response:

In case anyone else wants to try this...expand.grid is definitely the way to go. Still not sure how to deal with the nested loop from a coding perspective, but oh well..

n_c <- 1 
m_c <- 1
n_n <- 1
m_n <- 1
n_v <- 1

c = c(1,2)
n = c(10,20)
v = c(100,200)
parm_length = 3
iter = length(c)

test <- data.frame(matrix(ncol=parm_length, nrow=iter^parm_length)) 
test[] <- expand.grid(c,n,v)

x <- (test[,1] * n_c)/m_c
y <- (test[,2]* n_n)/m_n
z <- (test[,3]/n_v)

group <- cbind(test,x,y,z)
print(group)
  • Related