Conor
Conor

Reputation: 731

Julia: accumulating an array in a for loop (problem of local scope of loops)

I'm running into the problem of accumulating an array with a for-loop (my array is called condition_list, and each row stores a unique configuration of parameters).

The code below is what I'm imagining for building this array:

param1_vals = [1.0f0 2.0f0 3.0f0]; # specific values here don't matter
param2_vals = [1.0f0 2.0f0 3.0f0]; # specific values here don't matter
param3_vals = [1.0f0 2.0f0 3.0f0]; # specific values here don't matter

condition_list = zeros(Float32, 1, 3) # initialize condition_list

for ii = 1:length(param1_vals)
        for jj = 1:length(param2_vals)
                for kk = 1:length(param3_vals)
                        row_to_stack = [param1_vals[ii], param2_vals[jj], param3_vals[kk])
                        condition_list = vcat(condition_list, row_to_stack)
                end
         end
end

condition_list = condition_list[2:end,:] # pop off that first row (leftover of the initialization)

So each row of the resulting condition_list should have a unique configuration of each of the values of param1_vals , param2_vals , and param3_vals.

The issue I'm running into is about scope of local variables -- I get a condition_list is not defined error at the inner most line of the loop, when using vcat. What's the most Julian way to approach this problem, if I can't use an array accumulation? Or perhaps there's some solution using push! or something?

Also, is there a way you can accumulate an array without doing the stupid 'pop off the first row 'thing I did at the end? Can you start with a zero-row, 3 column array and accumulate rows onto it?

Upvotes: 2

Views: 1081

Answers (1)

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69869

A first comment is that maybe it is enough for you to have a lazy iterator of tuples. In this case it is enough if you write:

res = Iterators.product(param1_vals, param2_vals, param3_vals)

However, if you really need a matrix then run the following code on res:

mapreduce(x -> hcat(x...), vcat, res)

Now if you really wanted to work with something that you do in your code I would go with:

condition_vec = Matrix{Float32}[]

for ii = 1:length(param1_vals)
        for jj = 1:length(param2_vals)
                for kk = 1:length(param3_vals)
                        row_to_stack = [param1_vals[ii] param2_vals[jj] param3_vals[kk]]
                        push!(condition_vec, row_to_stack)
                end
         end
end

condition_list = reduce(vcat, condition_vec)

However, this code is a bit over-complicated as you could simply do:

condition_vec = Matrix{Float32}[]
for p1 = param1_vals, p2 = param2_vals, p3 = param3_vals
    push!(condition_vec, [p1 p2 p3])
end
condition_list = reduce(vcat, condition_vec)

without intermediate indexing.

Finally your code is not working as condition_list is a global variable and you would have to write:

global condition_list = vcat(condition_list, row_to_stack)

to make it work (note that there is a change coming to Julia and soon this will not be needed; this comment is for current 1.4.2 release of Julia, or other releases post 1.0 release).

Finally note that:

row_to_stack = [param1_vals[ii], param2_vals[jj], param3_vals[kk])

is an incorrect syntax (you used ) not ] at the end of the line). Also you use , not just spaces as in my code to separate values which would create you a column vector (not a matrix with 1-row as this is I guess what you wanted from your use of zeros function).

If you would have more questions regarding this code please ask in the comment.

Upvotes: 3

Related Questions