# First class "from end" indices into array

**URL:** https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455
**Category:** General Usage
**Created:** [June 11, 2024, 5:28am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455 "2024-06-11T05:28:52Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![shamazmazum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shamazmazum/32/25200_2.png) [@shamazmazum](https://discourse.julialang.org/u/shamazmazum)
#### Post date: [June 11, 2024, 5:28am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/1 "2024-06-11T05:28:52Z")

</div>

Is there any way to make a first class index that points to an element from the end of an array? So it can be e.g. assigned to a variable. For example, in python I can do

```py
idx1 = 0
idx2 = -1
a = [1,2,3,4,5]
a[idx1] # Gives 1
a[idx2] # Gives 5

```

In Julia one can use a special syntax with `end` keyword to access arrays from the end, but `end` has its special meaning only inside square brackets. Is there some way, e.g. a special type `FromEnd`, so I can write

```julia
idx = FromEnd(1)
a = [1,2,3,4,5]
a[idx] # Gives 5

indices = CartesianIndex(1):CartesianIndex(FromEnd(1)) # Gives all indices but the last

```

---

<div class="post-metadata">

### Author: ![StevenSiew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevensiew/32/218393_2.png) [@StevenSiew](https://discourse.julialang.org/u/StevenSiew)
#### Post date: [June 11, 2024, 5:35am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/2 "2024-06-11T05:35:02Z")

</div>

> [@shamazmazum](#):
>
> `a = [1,2,3,4,5]`

```julia
julia> a = [1,2,3,4,5]
5-element Vector{Int64}:
 1
 2
 3
 4
 5

julia> a[end]
5

julia> a[end-(2-1)]
4

julia> a[end-(3-1)]
3

julia> fromend(arr,n)=arr[end-(n-1)]
fromend (generic function with 1 method)

julia> fromend(a,4)
2

```

---

<div class="post-metadata">

### Author: ![shamazmazum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shamazmazum/32/25200_2.png) [@shamazmazum](https://discourse.julialang.org/u/shamazmazum)
#### Post date: [June 11, 2024, 5:40am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/3 "2024-06-11T05:40:53Z")

</div>

This is not what I want. In Python you do not have to know the array to create an index into that array. Please notice a difference between

```py
a[-1]

```

and

```julia
a[fromend(a,1)]

```

In the first case `a` appears only once.

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [June 11, 2024, 5:50am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/4 "2024-06-11T05:50:23Z")

</div>

You can use the `to_indices` mechanism to do this:

```julia-repl
julia> struct FromEnd
       i::Int
       end

julia> Base.to_indices(A, inds, I::Tuple{FromEnd, Vararg}) = (@inline; (last(inds[1])-I[1].i, to_indices(A, Base.safe_tail(inds), Base.tail(I))...))

julia> I = FromEnd(2)
FromEnd(2)

julia> arr = reshape(1:15, 5, 3)
5×3 reshape(::UnitRange{Int64}, 5, 3) with eltype Int64:
 1 6 11
 2 7 12
 3 8 13
 4 9 14
 5 10 15

julia> arr[:,I]
5-element Vector{Int64}:
 1
 2
 3
 4
 5

julia> arr[I,:]
3-element Vector{Int64}:
  3
  8
 13

```

Edit: This is not a full solution, just a proof-of-concept.

---

<div class="post-metadata">

### Author: ![StevenSiew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevensiew/32/218393_2.png) [@StevenSiew](https://discourse.julialang.org/u/StevenSiew)
#### Post date: [June 11, 2024, 5:50am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/5 "2024-06-11T05:50:52Z")

</div>

The answer is no.  
There is no firstclass negative index in Julia.  
The best you can do is  
a[end-(1-1)] for a[-1]  
a[end-(2-1)] for a[-2]  
a[end-(3-1)] for a[-3]

---

<div class="post-metadata">

### Author: ![shamazmazum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shamazmazum/32/25200_2.png) [@shamazmazum](https://discourse.julialang.org/u/shamazmazum)
#### Post date: [June 11, 2024, 6:10am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/6 "2024-06-11T06:10:43Z")

</div>

> [@abraemer](#):
>
> ```julia
> julia> struct FromEnd
> i::Int
> end
> 
> julia> Base.to_indices(A, inds, I::Tuple{FromEnd, Vararg}) = (@inline; (last(inds[1])-I[1].i, to_indices(A, Base.safe_tail(inds), Base.tail(I))...))
> 
> julia> I = FromEnd(2)
> FromEnd(2)
> 
> julia> arr = reshape(1:15, 5, 3)
> 5×3 reshape(::UnitRange{Int64}, 5, 3) with eltype Int64:
> 1 6 11
> 2 7 12
> 3 8 13
> 4 9 14
> 5 10 15
> 
> julia> arr[:,I]
> 5-element Vector{Int64}:
> 1
> 2
> 3
> 4
> 5
> 
> julia> arr[I,:]
> 3-element Vector{Int64}:
> 3
> 8
> 13
> 
> ```

Cool, thanks. But since UnitRange has kind \* → \* (i.e. it has only one parameter), it’s fundamentally impossible to write something like x:FromEnd(y), isn’t it?

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [June 11, 2024, 6:15am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/7 "2024-06-11T06:15:49Z")

</div>

> [@shamazmazum](#):
>
> x:FromEnd(y)

Well for this to work you’d need to hook into `UnitRange` and the like which likely will be very messy and doesn’t sound like a great idea to me. The problem is that a `UnitRange` is concept separate from indexing that doesn’t really make sense without a well-defined endpoint.

Edit: Ofc it’s not “fundamentally impossible” to do what you ask - the question is rather “How much effort do you need?”. For the mixed ranges to work, you probably need another type.

---

<div class="post-metadata">

### Author: ![shamazmazum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shamazmazum/32/25200_2.png) [@shamazmazum](https://discourse.julialang.org/u/shamazmazum)
#### Post date: [June 11, 2024, 6:21am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/8 "2024-06-11T06:21:45Z")

</div>

OK, thanks! Also, ranges like that are not supported in python either:

```julia
>>> 0:-1
  File "<stdin>", line 1
    0:-1
    ^
SyntaxError: illegal target for annotation

```

---

<div class="post-metadata">

### Author: ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)
#### Post date: [June 11, 2024, 6:27am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/9 "2024-06-11T06:27:06Z")

</div>

Are you OK with not using the `getindex` / `[]` syntax directly?

If yes, what about a variation of this (with a better name)?

```julia
function getindex_potentially_from_end(a, i)
    if i > 0
        return a[i]
    else
        return a[end + i]
    end
end

```

Of course this particular example probably only works with standard 1-based vectors, but it just requires one function and no extra types. Just as an idea.

---

<div class="post-metadata">

### Author: ![shamazmazum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shamazmazum/32/25200_2.png) [@shamazmazum](https://discourse.julialang.org/u/shamazmazum)
#### Post date: [June 11, 2024, 6:31am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/10 "2024-06-11T06:31:21Z")

</div>

It can be a solution, but it breaks Julia syntax for indexing ☹ I like @abraemer 's solution more

---

<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: [June 11, 2024, 6:39am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/11 "2024-06-11T06:39:25Z")

</div>

EndpointRanges.jl provides something like this:

```julia
julia> a = [1,2,3,4,5]
5-element Vector{Int64}:
 1
 2
 3
 4
 5

julia> a[iend]
5

julia> idx2 = iend
EndpointRanges.IEnd()

julia> a[idx2]
5

```

---

<div class="post-metadata">

### Author: ![shamazmazum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shamazmazum/32/25200_2.png) [@shamazmazum](https://discourse.julialang.org/u/shamazmazum)
#### Post date: [June 11, 2024, 6:45am UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/12 "2024-06-11T06:45:34Z")

</div>

This is great!

---

<div class="post-metadata">

### Author: ![savq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/savq/32/22063_2.png) [@savq](https://discourse.julialang.org/u/savq)
#### Post date: [June 11, 2024, 10:06pm UTC](https://discourse.julialang.org/t/first-class-from-end-indices-into-array/115455/13 "2024-06-11T22:06:45Z")

</div>

When used as indices, the keywords `begin` and `end` desugar to [`firstindex`](https://docs.julialang.org/en/v1/base/collections/#Base.firstindex) and [`lastindex`](https://docs.julialang.org/en/v1/base/collections/#Base.lastindex) respectively.

We can confirm that ourselves with `Meta.@lower`:

```julia-repl
julia> Meta.@lower begin
           vec[end]
       end
:($(Expr(:thunk, CodeInfo(
    @ REPL[7]:2 within `top-level scope`
1 ─ %1 = vec
│ %2 = Base.lastindex(vec)
│ %3 = Base.getindex(%1, %2)
└── return %3
))))

```
