# Accessing multi-dimensional arrays in 1 go

**URL:** <https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641>\
**Category:** General Usage\
**Tags:** question, array\
**Created:** [September 15, 2020, 2:27pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641 "2020-09-15T14:27:44Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)\
**Post date:** [September 15, 2020, 2:27pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641/1 "2020-09-15T14:27:44Z")

</div>

I am trying to figure out if there is an easy (and quick) way of accessing elements of a multi-dimensional array according to multi-dimensional array of indices.

For example:

```julia
A = reshape(1:8,2,2,2);
indxs = repeat([1],1,2,2);

```

I would like it to output

```julia
Mat = zeros(size(indxs,1),size(A,2),size(A,3));
for i=1:size(A,2)
     for j=1:size(A,3)
          Mat[:,i,j] = A[indxs[:,i,j],i,j];
     end
end

```

whose output is

```julia
[:, :, 1] =
 1.0 3.0

[:, :, 2] =
 5.0 7.0

```

all in one go, so I try

```julia
A[indxs,[1;2],[1;2]] 

```

but, what I thought would work is off (it adds dimensions by doing all pair-wise combinations):

```julia
[:, :, 1, 1, 1] =
 1 1
[:, :, 2, 1, 1] =
 1 1
[:, :, 1, 2, 1] =
 3 3
[:, :, 2, 2, 1] =
 3 3
[:, :, 1, 1, 2] =
 5 5
[:, :, 2, 1, 2] =
 5 5
[:, :, 1, 2, 2] =
 7 7
[:, :, 2, 2, 2] =
 7 7

```

Any ideas if what I want exists?

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [September 15, 2020, 2:43pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641/2 "2020-09-15T14:43:29Z")

</div>

> [@danicaratelli](#):
>
> `Mat[:,i,j] = A[indxs[:,i,j],i,j];`

Nothing wrong with writing loops, although I’d write a 3rd one, since here `A[indxs[:,1,2],1,2] isa Array` which you need not create. I also have a package you may like, which does exactly that:

```julia
@tullio Mat2[c,i,j] := A[indxs[c,i,j],i,j]
Mat2 == Mat

```

---

<div class="post-metadata">

**Author:** ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)\
**Post date:** [September 15, 2020, 3:00pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641/3 "2020-09-15T15:00:59Z")

</div>

I was hoping there was a way to do it without resorting to loops, just a matter of indexation but haven’t found a way yet.

Thank you for your suggestion, however, in this context

> [@mcabbott](#):
>
> ```julia
> @tullio Mat2[c,i,j] := A[indxs[c,i,j],i,j]
> Mat2 == Mat
> 
> ```

appears to be slower than the loop.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [September 15, 2020, 3:20pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641/4 "2020-09-15T15:20:11Z")

</div>

You may like [What to do about nonscalar indexing? · Issue #30845 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/30845) for discussion of whether to make things like `A.[indxs, :, :]` mean something. But as you’ve observed, right now `A[indxs, :, :]` adds dimensions.

Maybe there’s a clever way of broadcasting `getindex`. I guess you can write a comprehension:

```julia
[A[indxs[I], I.I[2:end]...] for I in CartesianIndices(indxs)]

```

> [@danicaratelli](#):
>
> appears to be slower than the loop.

Are you sure? I get it’s about 3x faster at this size, and with everything 100x100x100.

---

<div class="post-metadata">

**Author:** ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)\
**Post date:** [September 15, 2020, 3:25pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641/5 "2020-09-15T15:25:26Z")

</div>

> [@mcabbott](#):
>
> Are you sure? I get it’s about 3x faster at this size, and with everything 100x100x100.

I tried this:

```julia
M = 50; T = 20; N = M*T*20;
A = reshape(1:N,Int(N/(M*T)),M,T);
indxs = rand(1:Int(N/(M*T)),Int(N/(M*T)),M,T);

@time begin
Mat = zeros(size(indxs,1),size(A,2),size(A,3)); 
for i=1:size(A,2)
     for j=1:size(A,3)
          Mat[:,i,j] = A[indxs[:,i,j],i,j];
     end
end
end

@time @tullio Mat2[c,i,j] := A[indxs[c,i,j],i,j];

```

and the times were 0.001876 seconds vs. 0.363211 seconds. But I might have done something wrong.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [September 15, 2020, 3:46pm UTC](https://discourse.julialang.org/t/accessing-multi-dimensional-arrays-in-1-go/46641/6 "2020-09-15T15:46:48Z")

</div>

OK, I think that is mostly the time of generating the code, which should happen once. Using [GitHub - JuliaCI/BenchmarkTools.jl: A benchmarking framework for the Julia language](https://github.com/JuliaCI/BenchmarkTools.jl) and being careful about globals, at these sizes, I get:

```julia
julia> @btime @tullio Mat2[c,i,j] := $A[$indxs[c,i,j],i,j];
  27.247 μs (3 allocations: 156.38 KiB)

julia> @btime [$A[$indxs[I], I.I[2:end]...] for I in CartesianIndices($indxs)];
  84.033 μs (2 allocations: 156.33 KiB)

julia> @btime f1($A, $indxs); # as in original post
  153.832 μs (2002 allocations: 625.08 KiB)

```

The last two can be made quicker with `@inbounds`, but perhaps with a check that `issubset(extrema(indxs), axes(A,1))` first.
