# Index into N-dimensional array with N indices

**URL:** <https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989>\
**Category:** General Usage\
**Created:** [October 20, 2022, 2:10am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989 "2022-10-20T02:10:06Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![torrance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torrance/32/38990_2.png) [@torrance](https://discourse.julialang.org/u/torrance)\
**Post date:** [October 20, 2022, 2:10am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989/1 "2022-10-20T02:10:06Z")

</div>

Given an N-dimensional (custom) array `A <: AbstractArray{T, N}`, I want to index into this with N indices:

eg. if `A <: AbstractArray{T, 2}` I want `A[:, :]` or if `A <: AbstractArray{T, 3}` I want `A[:, :, :]`

This is a custom array that is _strictly_ cartesian, so simply doing `A[:]` for linear indexing won’t work.

How do I programmatically do this? I’m assuming I need some metaprogramming here?

---

<div class="post-metadata">

**Author:** ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)\
**Post date:** [October 20, 2022, 2:26am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989/2 "2022-10-20T02:26:55Z")

</div>

If all indexers are `:`, you’d just use `copy(A)` instead of `A[:, :, ...]`.

However, as you asked this question, I’d suppose it was not an XY problem and what you expected could be the way to programmatically create indexing for variable dimensional arrays.

A zero-cost way is to use `ntuple`.

Given `N` is the type parameter comes from where clauses like,

```julia
function myfunc(A::TArray) where {N, T, TArray <: AbstractArray{T, N}}

```

We could use `ntuple` to generate the code we want:

```julia
# e.g., `ntuple(i -> :, 3)` creates a **constant** `(:, :, :)`

A[ntuple(dim -> :, N)...]

```

Let us make this example more representative, for instance, index `1` for the first dimension, and `:` for the left:

```julia
A[ntuple(dim -> dim == 1 ? 1 : (:), N)...]

```

The generation is static, which can be seen from the generated code:

```julia
f(A::AbstractArray{T, N}) where {T, N} = A[ntuple(dim -> dim == 1 ? 1 : (:), N)...]
g(A) = A[1, :, :]

A = rand(3, 3, 3)

```

We can find the generated code is identity:

> **@code\_typed g(A)**
>
> ```julia
> julia> @code_typed g(A)
> CodeInfo(
> 1 ─ Base.arraysize(A, 1)::Int64
> │ %2 = Base.arraysize(A, 2)::Int64
> │ %3 = Base.arraysize(A, 3)::Int64
> │ %4 = Base.slt_int(%2, 0)::Bool
> │ %5 = Base.ifelse(%4, 0, %2)::Int64
> │ %6 = %new(Base.OneTo{Int64}, %5)::Base.OneTo{Int64}
> │ %7 = Base.slt_int(%3, 0)::Bool
> │ %8 = Base.ifelse(%7, 0, %3)::Int64
> │ %9 = %new(Base.OneTo{Int64}, %8)::Base.OneTo{Int64}
> │ %10 = %new(Base.Slice{Base.OneTo{Int64}}, %6)::Base.Slice{Base.OneTo{Int64}}
> │ %11 = %new(Base.Slice{Base.OneTo{Int64}}, %9)::Base.Slice{Base.OneTo{Int64}}
> └── goto #6 if not true
> 2 ─ %13 = Core.tuple(1, %10, %11)::Tuple{Int64, Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}}
> │ %14 = Base.arraysize(A, 1)::Int64
> │ Base.arraysize(A, 2)::Int64
> │ Base.arraysize(A, 3)::Int64
> │ %17 = Base.slt_int(%14, 0)::Bool
> │ %18 = Base.ifelse(%17, 0, %14)::Int64
> │ %19 = Base.sle_int(1, 1)::Bool
> │ %20 = Base.sle_int(1, %18)::Bool
> │ %21 = Base.and_int(%19, %20)::Bool
> │ %22 = Base.and_int(%21, true)::Bool
> └── goto #4 if not %22
> 3 ─ Base.nothing::Nothing
> └── goto #5
> 4 ─ invoke Base.throw_boundserror(A::Array{Float64, 3}, %13::Tuple{Int64, Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}})::Union{}
> └── unreachable
> 5 ─ nothing::Nothing
> 6 ┄ %29 = invoke Base._unsafe_getindex($(QuoteNode(IndexLinear()))::IndexLinear, A::Array{Float64, 3}, 1::Int64, %10::Base.Slice{Base.OneTo{Int64}}, %11::Base.Slice{Base.OneTo{Int64}})::Matrix{Float64}
> └── goto #7
> 7 ─ goto #8
> 8 ─ return %29
> ) => Matrix{Float64}
> 
> ```

> **@code\_typed f(A)**
>
> ```julia
> julia> @code_typed f(A)
> CodeInfo(
> 1 ─ Base.arraysize(A, 1)::Int64
> │ %2 = Base.arraysize(A, 2)::Int64
> │ %3 = Base.arraysize(A, 3)::Int64
> │ %4 = Base.slt_int(%2, 0)::Bool
> │ %5 = Base.ifelse(%4, 0, %2)::Int64
> │ %6 = %new(Base.OneTo{Int64}, %5)::Base.OneTo{Int64}
> │ %7 = Base.slt_int(%3, 0)::Bool
> │ %8 = Base.ifelse(%7, 0, %3)::Int64
> │ %9 = %new(Base.OneTo{Int64}, %8)::Base.OneTo{Int64}
> │ %10 = %new(Base.Slice{Base.OneTo{Int64}}, %6)::Base.Slice{Base.OneTo{Int64}}
> │ %11 = %new(Base.Slice{Base.OneTo{Int64}}, %9)::Base.Slice{Base.OneTo{Int64}}
> └── goto #6 if not true
> 2 ─ %13 = Core.tuple(1, %10, %11)::Tuple{Int64, Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}}
> │ %14 = Base.arraysize(A, 1)::Int64
> │ Base.arraysize(A, 2)::Int64
> │ Base.arraysize(A, 3)::Int64
> │ %17 = Base.slt_int(%14, 0)::Bool
> │ %18 = Base.ifelse(%17, 0, %14)::Int64
> │ %19 = Base.sle_int(1, 1)::Bool
> │ %20 = Base.sle_int(1, %18)::Bool
> │ %21 = Base.and_int(%19, %20)::Bool
> │ %22 = Base.and_int(%21, true)::Bool
> └── goto #4 if not %22
> 3 ─ Base.nothing::Nothing
> └── goto #5
> 4 ─ invoke Base.throw_boundserror(A::Array{Float64, 3}, %13::Tuple{Int64, Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}})::Union{}
> └── unreachable
> 5 ─ nothing::Nothing
> 6 ┄ %29 = invoke Base._unsafe_getindex($(QuoteNode(IndexLinear()))::IndexLinear, A::Array{Float64, 3}, 1::Int64, %10::Base.Slice{Base.OneTo{Int64}}, %11::Base.Slice{Base.OneTo{Int64}})::Matrix{Float64}
> └── goto #7
> 7 ─ goto #8
> 8 ─ return %29
> ) => Matrix{Float64}
> 
> ```

---

<div class="post-metadata">

**Author:** ![torrance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torrance/32/38990_2.png) [@torrance](https://discourse.julialang.org/u/torrance)\
**Post date:** [October 20, 2022, 2:27am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989/3 "2022-10-20T02:27:44Z")

</div>

To answer my own question, use [Base.Cartesian · The Julia Language](https://docs.julialang.org/en/v1/devdocs/cartesian/)

e.g.:

```julia
@generated function test(A::Array{T, N}) where {T, N}
   quote
       Base.Cartesian.@nref $N A j->(i_j = Colon())
   end
end

```

---

<div class="post-metadata">

**Author:** ![torrance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torrance/32/38990_2.png) [@torrance](https://discourse.julialang.org/u/torrance)\
**Post date:** [October 20, 2022, 2:29am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989/4 "2022-10-20T02:29:17Z")

</div>

@thautwarm Appreciate your answer here - I did not know about the `ntuple(f, N)` function - that’s a nice tidy way to do this too!

---

<div class="post-metadata">

**Author:** ![torrance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torrance/32/38990_2.png) [@torrance](https://discourse.julialang.org/u/torrance)\
**Post date:** [October 20, 2022, 2:33am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989/5 "2022-10-20T02:33:16Z")

</div>

@thautwarm In fact, I’m marking yours as the solution because it’s much simpler and elegant than some Base.Cartesian.

(As an aside, yes, `copy()` would normally be the right way to do this, but in actual fact this is to implement `copy()` for a custom array.)

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [October 20, 2022, 2:50am UTC](https://discourse.julialang.org/t/index-into-n-dimensional-array-with-n-indices/88989/6 "2022-10-20T02:50:23Z")

</div>

You may look at [GitHub - SciML/EllipsisNotation.jl: Implements the notation `..` for indexing arrays.](https://github.com/SciML/EllipsisNotation.jl) as well
