# Multiple loops

Hello,

I tried to write some code on multiple but unknown number of loops. But didn’t find ways to do it. Can someone give me a hint? Thanks in advanced.
Suppose I have an array

``````a = [2,3,4,5]
``````

I want to write a loop that is equivalent to the following

``````A = Array{Array{Int64}}(undef,0)
for i_1 in 1:a
for i_2 in 1:a
for i_3 in 1:a
for i_4 in 1:a
append!(A,[[i_1,i_2,i_3,i_4]])
end
end
end
end
``````

output will be

``````A
144-element Array{Array{Int64,N} where N,1}:
[1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 1, 3]
[1, 1, 1, 4]
[1, 1, 1, 5]
[1, 1, 2, 1]
[1, 1, 2, 2]
[1, 1, 2, 3]
[1, 1, 2, 4]

.
.
.
``````

But in a more general way, so that it will also can deal with for other 1D arrays like

``````a = [2,3,4,5,6]
a = [2,3,4,5,6,7]
``````

Baicai

I think this may be useful:
https://julialang.org/blog/2016/02/iteration

2 Likes

You might want to use macros to generate multiple loops if the size of `a` is known at compile time.

with some tricks and the comments above, i did an awfully looking function that does what you requested, maybe it can be of some help

``````function testfunc(x::Array{II,1}) where II <: Integer
A = Array{Array{Int64,1},1}(undef,reduce(*,x)) #prealocate array
A0 = Array{Int8,length(x)}(undef,tuple(x...)...)
#this matrix have in his indices the values that we want

k = 1
for idx in CartesianIndices(A0)
A[k] = vcat(Tuple(idx)...)
#tried to use collect, the error message recommended this
k +=1
end
return A
end`
``````

Use recursion. Metaprogramming and Cartesians can work, but it’s just overkill and much more complex than a simple recursive implementation.

5 Likes

I believe this solution iterates in the wrong order, it should be the last index incrementing first:

``````julia> testfunc([2,3,4])
24-element Array{Array{Int64,1},1}:
[1, 1, 1]
[2, 1, 1]
[1, 2, 1]
[2, 2, 1]
[1, 3, 1]
[2, 3, 1]
[1, 1, 2]
...
``````

Here’s one attempt that uses `Iterators.product`:

``````function myprod(v)
x = [1:n for n in reverse(v)]
return vec([[reverse(p)...] for p in Iterators.product(x...)])
end
``````

It gets complicated because you want to increment the last elements first. Otherwise you could drop the `reverse` calls.

You could optimize it in various ways: using `Iterators.reverse(v)` instead of `reverse(v)`, if you could use tuples instead of vectors you wouldn’t need to splat `[reverse(p)...]`, and so on.

EDIT: oups, @DNF proposed a similar solution based on `Iterators.product` 2min earlier already!

Here is a simple solution for the specific case of your question. It doesn’t output exactly what you asked for, but can easily be adjusted:

``````julia> foreach(Iterators.product((1:x for x in a)...)) do i
push!(A, [i...])
end

julia> A
120-element Array{Array{Int64,N} where N,1}:
[1, 1, 1, 1]
[2, 1, 1, 1]
[1, 2, 1, 1]
[2, 2, 1, 1]
[1, 3, 1, 1]
[2, 3, 1, 1]
[1, 1, 2, 1]
[2, 1, 2, 1]
[1, 2, 2, 1]
[2, 2, 2, 1]
[1, 3, 2, 1]
[2, 3, 2, 1]
[1, 1, 3, 1]
[2, 1, 3, 1]
[1, 2, 3, 1]
[2, 2, 3, 1]
[1, 3, 3, 1]
[2, 3, 3, 1]
[1, 1, 4, 1]
[2, 1, 4, 1]
[1, 2, 4, 1]
⋮
``````

BTW, it is a bit important to realize that `Array{Int}` is an abstract type, and using this can make a negative impact on performance, and even introduce bugs.

If you want a one-dimensional array, you have to write `Array{Int, 1}`, not `Array{Int}`. This is also why I recommend using `Vector{Int}` and `Matrix{Int}`, instead of `Array`. It is too easy to forget the dimension parameter, and it’s also harder to read.

1 Like

another implementation, using a looped_counter function that gives the next element, using recursion, you can add the type annotations and size checks to improve performance later, but this proof of concept works and gives you the order that you want

``````function looped_counter(x0,xmin, xmax,k=length(x0))
x = copy(x0)
k == 0 && return copy(xmin)
if x[k]==xmax[k]
x[k] = xmin[k]
looped_counter(x,xmin,xmax,k-1)
elseif x[k]<xmax[k]
x[k]+=1
return x
else
throw("wtf")
end
end

function myfunc(xmin,xmax)
A = Array{Array{Int64,1},1}(undef,0)
a = copy(xmin)
a = looped_counter(a,xmin,xmax)
while a!= xmin
push!(A,a)
a = looped_counter(a,xmin,xmax)
end
return A
end
``````

a simple example:

``````xmin = [1,1,1]
xmax = [3,4,3]
myfunc[xmin,xmax]

35-element Array{Array{Int64,1},1}:
[1, 1, 2]
[1, 1, 3]
[1, 2, 1]
[1, 2, 2]
[1, 2, 3]
[1, 3, 1]
[1, 3, 2]
[1, 3, 3]
[1, 4, 1]
[1, 4, 2]
[1, 4, 3]
[2, 1, 1]
⋮
[3, 1, 2]
[3, 1, 3]
[3, 2, 1]
[3, 2, 2]
[3, 2, 3]
[3, 3, 1]
[3, 3, 2]
[3, 3, 3]
[3, 4, 1]
[3, 4, 2]
[3, 4, 3]
``````

an advantage of the implementation is that you can use a different xmin to give different results (and it can be used as a clock, IDK)