# Loops for unknown numbers of inputs

Hello!
Now I am trying to make functions to form a matrix which can traverse all the values of input. Can you help with that?
Suppose that we have three arrays:

``````as = [1,2]
bs = [3,4, 5]
cs = 
``````

Then I want to build a matrix that includes all the possible combinations

``````nloop = length(as) * length(bs) * length(cs)
num_set = zeros(nloop, 3)
loop_num = 1
for (ia, va) in enumerate(as), (ib, vb) in enumerate(bs), (ic, vc) in enumerate(cs)
num_set[loop_num, :] .= [va,vb,vc]
global loop_num += 1
end
``````

then output should be:

``````6×3 Matrix{Float64}:
1.0  3.0  6.0
2.0  3.0  6.0
1.0  4.0  6.0
2.0  4.0  6.0
1.0  5.0  6.0
2.0  5.0  6.0
``````

What if I have few inputs of sets, for example:

``````as = [1,2]
bs = [3,4, 5]
cs = 
ds = [7, 8, 9]
``````

How can I create a function to form a few loops according to the number of number sets? Many thanks in advance!

I am surprised that Combinatorics.jl doesn’t have this functionality already?

Maybe `Iterators.product` can help you out (also see `zip`)

Thank you! I would check `Iterators.product ` .

`Iterators.product` can solve my problem! But how can I transform the Array to Matrix{Float64}？

This is most definitely not the most efficient way, but this matches your original output:

``````mapreduce(collect,hcat,Iterators.product(as,bs,cs))'
``````
1 Like

It is more efficient and natural to turn it into a `3 x nloops` matrix instead of an `nloops x 3` matrix, since Julia arrays are column major and the tuples are adjacent in memory. In that case:

``````julia> reshape(reinterpret(Int, collect(Iterators.product(as, bs, cs))), 3, :)
3×6 reshape(reinterpret(Int64, ::Array{Tuple{Int64, Int64, Int64}, 3}), 3, 6) with eltype Int64:
1  2  1  2  1  2
3  3  4  4  5  5
6  6  6  6  6  6
``````

(On my laptop that’s >6x as fast as the `mapreduce`.)

1 Like

Thank you! really helpful!

Thank you!

just for fun

``````function hmprod(v...)
prod=[]
for a in v, b in v
push!(prod, [a...,b])
end
prod
end

``````
1 Like

Thank you! I am wondering how `for a in v, b in v` can work for unknown numbers of inputs. Seems I should read more about `...`. BTW, your code is more friendly for mixed types of input arrays. Thank you all!

I’m not sure I fully understand your doubt, but the script, which is certainly not as efficient as the other proposals, should work for a generic number of input vectors.

``````julia> as = [1,2]
2-element Vector{Int64}:
1
2

julia> bs = (3,4, 5)
(3, 4, 5)

julia> cs = 
1-element Vector{Int64}:
6

julia> ds = [7, 8, 9]
3-element Vector{Int64}:
7
8
9

4-element Vector{Any}:
[1, 2]
(3, 4, 5)

[7, 8, 9]

18-element Vector{Any}:
(1, 3, 6, 7)
(1, 3, 6, 8)
(1, 3, 6, 9)
(1, 4, 6, 7)
(1, 4, 6, 8)
(1, 4, 6, 9)
(1, 5, 6, 7)
(1, 5, 6, 8)
(1, 5, 6, 9)
(2, 3, 6, 7)
(2, 3, 6, 8)
(2, 3, 6, 9)
(2, 4, 6, 7)
(2, 4, 6, 8)
(2, 4, 6, 9)
(2, 5, 6, 7)
(2, 5, 6, 8)
(2, 5, 6, 9)

julia> function hmprod(v...)
p=[]
i=1
for a in v, b in v
push!(p, (a...,b))
i+=1
end
p
end
hmprod (generic function with 1 method)
``````

I add a recursive version, which does not use functions of either Base or other packages.

``````julia> function rhmprod(v...)
p=Tuple[]
i=1
if length(v)>=2
for a in v, b in v
push!(p, (a...,b))
i+=1
end
rhmprod(p,v[3:end]...)
else
v
end
end
rhmprod (generic function with 1 method)

18-element Vector{Tuple}:
(1, 3, 6, 7)
(1, 3, 6, 8)
(1, 3, 6, 9)
(1, 4, 6, 7)
(1, 4, 6, 8)
(1, 4, 6, 9)
(1, 5, 6, 7)
(1, 5, 6, 8)
(1, 5, 6, 9)
(2, 3, 6, 7)
(2, 3, 6, 8)
(2, 3, 6, 9)
(2, 4, 6, 7)
(2, 4, 6, 8)
(2, 4, 6, 9)
(2, 5, 6, 7)
(2, 5, 6, 8)
(2, 5, 6, 9)
``````
1 Like

Thank you! I can understand your code now. but why we need the `i` to count the loop?

It does not have anything to do with it.
It’s just the remnant of a “refactoring” .

PS
consider that the solution based on the use of the product function is much, much better performing.

1 Like