Loops with arrays of arbitrary dimensions

Assume that I have a 2D array A and I want to do something like this

N1, N2 = 4, 3
A = ones((N1, N2))

x = zeros(N1)
for i2=1:N2
    for i1=1:N1
        x[i1] = 2 * A[i1, i2]
    end
end

x = zeros(N2)
for i1=1:N1
    for i2=1:N2
        x[i2] = 2 * A[i1, i2]
    end
end

Then, in case of 3D array A I will need to add one extra loop:

N1, N2, N3 = 4, 3, 2
A = ones((N1, N2, N3))

x = zeros(N1)
for i3=1:N3
for i2=1:N2
    for i1=1:N1
        x[i1] = 2 * A[i1, i2, i3]
    end
end
end

# etc.

Now let’s assume I have an n-dimensional array A, and I want to specify some axis ax along which I want to multiply A by 2 and put the result to x (similarly to the above examples). The corresponding pseudo code can look like

ax = m

A = zeros((N1, N2, ..., Nn))

x = zeros(Nm)

for in=1:Nn
for i(n-1)=1:N(n-1)
...
for i(m+1)=1:N(m+1)
for i(m-1)=1:N(m-1)
...
for i2=1:N2
for i1=1:N1
    for im=1:Nm
        x[im] = 2 * A[i1, i2, ..., i(m-1), im, i(m+1), ..., i(n-1), in]
    end
end
end
...
end
end
...
end
end

However, I want a generic code which will not depend on the number of A dimensions, i.e. some function foo(x, A, ax) which will do what I want independently of the size of A. How I should write such kind of code with loops for arbitrary dimension of A?
So far I found only this old blog post which proposes to use macros. Did something changed since then? Can the corresponding loops be written with ndims and axes functions without macro?

You are looking for CartisianIndices

julia> x2 = rand(2, 2);

julia> x3 = rand(2, 2, 2);

julia> for c in CartesianIndices(x2)
           @show x2[c]
       end
x2[c] = 0.4108577974629497
x2[c] = 0.4591618516787277
x2[c] = 0.22742754395597542
x2[c] = 0.9850643176704423

julia> for c in CartesianIndices(x3)
           @show x3[c]
       end
x3[c] = 0.2229783161443213
x3[c] = 0.4984591608388653
x3[c] = 0.4418623143086191
x3[c] = 0.6718510628390104
x3[c] = 0.21610541455088628
x3[c] = 0.574532213871789
x3[c] = 0.02381508624762918
x3[c] = 0.9172113813322624

There is also @nloops [1]

[1] Base.Cartesian · The Julia Language

Can you please give me an example how I can write, let say, the following loop in terms of CartesianIndices:

N1, N2 = 4, 3
A = ones((N1, N2))

x = zeros(N1)
for i2=1:N2
    for i1=1:N1
        x[i1] = 2 * A[i1, i2]
    end
end

CartesianIndices(A) and CartesianIndices(x) have different dimensions.

I think this might be an XY problem. In the example above, you are overwriting x many times. Do you mean to have a += intead of an =?

Assuming this is what you want to do, you would write it like this:

for I in CartesianIndices(A)
    i1 = I[1]
    x[i1] = 2 * A[I]
end
4 Likes

Its just a fake example which came to my mind. It can be either of them.

Then @jipolanco 's solution above is what you want.

Thank you. Seems like what I need.
Just a small question. Why do I need to take Tuple of I? It seems to work with just I[1].

Oops, you’re totally right about that! I wasn’t sure that it worked.

Thank you all guys for the help.