# End keyword in creating CartesianIndex

**URL:** https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461
**Category:** Internals & Design
**Tags:** question, array
**Created:** [October 29, 2019, 8:57pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461 "2019-10-29T20:57:08Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)
#### Post date: [October 29, 2019, 8:57pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/1 "2019-10-29T20:57:08Z")

</div>

I created an issue regarding `end` keyword in creating `CartesianIndex` in Julia repository a while ago ([end keyword in creating CartesianIndex · Issue #33608 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/33608)):

* * *

It is not possible to create a `CartesianIndex` object using `end` keyword.

This following code does not work in Julia:

```julia
CartesianIndex(end,1)

```

In Python, this is possible using `-1` indexing:

```python
import numpy
arr= numpy.array([[4, 2, 3], [2, 5, 4]])
ind=(-1,1) # similar to CartesianIndex
arr[ind]

```

This is useful for creating algorithms that are independent of the array, such as for `sortperm(A, dim)` [issue open since 2016](https://github.com/JuliaLang/julia/issues/16273)

* * *

And I got a response from @Keno that:

> You can definitely create a type that behaves like this, it just doesn’t have the same semantics as `end` which is defined to looks for the innermost enclosing array (so it does do what you want if you construct the Cartesian index inside the array access). Closing, since this conflicts with `end`s semantics, but I would encourage you to try writing the type that behaves like this yourself. It shouldn’t be more than 15 lines of code. If you need help, feel free to open a thread on discourse.

How can I do this?

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [October 29, 2019, 9:16pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/2 "2019-10-29T21:16:17Z")

</div>

The basic technique Keno was referencing is something that’s generally quite feasible, and I think there is a package _somewhere_ that does it (but I cannot find it at the moment).

```nohighlight
julia> struct End end

julia> Base.to_indices(A, inds, I::Tuple{End, Vararg}) = (inds[1][end], to_indices(A, Base.tail(inds), Base.tail(I))...)

```

With just those two definitions, we can now use `End()` in many places that didn’t use to be possible:

```nohighlight
julia> A = rand(3,5)
3×5 Array{Float64,2}:
 0.0496429 0.1541 0.178673 0.987561 0.100913
 0.273997 0.984579 0.255768 0.862814 0.200435
 0.317385 0.445612 0.106676 0.00631464 0.934804

julia> A[End(), 2]
0.4456115553735922

julia> view(A, End(), 2:3)
2-element view(::Array{Float64,2}, 3, 2:3) with eltype Float64:
 0.4456115553735922
 0.10667647668776192

```

Now, the trouble you’ll rapidly run into is that you cannot do computation on this `End()` thing.

```nohighlight
julia> A[End() - 1, :]
ERROR: MethodError: no method matching -(::End, ::Int64)

```

So you can manually add in “deferred” computations, essentially allowing it to build up a thunk that it can evaluate once it knows the size of the array. This is the huge advantage to the `end` keyword — it is just syntax for the appropriate `lastindex` function call, which returns a _real_ integer on which you can do real computation.

* * *

Now this finally brings us to your actual question, which is can you use this thing with a `CartesianIndex`? The answer there is a flat no. `CartesianIndex` is hardcoded to only handle `Int`s. But the game isn’t over — you can of course construct your own type that will work _just like_ CartesianIndex but allow for more things to be stored in it. It’s just a bit more complicated, but that [`to_indices`](https://docs.julialang.org/en/v1/base/arrays/#Base.to_indices) is the only API that you need to extend.

---

<div class="post-metadata">

### Author: ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)
#### Post date: [October 29, 2019, 9:25pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/3 "2019-10-29T21:25:48Z")

</div>

So `CartesianIndex(End(), 1)` doesn’t work?

I don’t want to mix issues, but as an example, `sortperm(A, dim)` [issue open since 2016](https://github.com/JuliaLang/julia/issues/16273) is implemented in Numpy by using [this `-1` syntax](https://github.com/numpy/numpy/blob/07a7eb5b0ce9b5a6fb178ee61a758491afb24273/numpy/lib/shape_base.py#L48). I think this features should be added to CartesianIndex, otherwise the algorithms become complex.

> **Non-working copy**
>
> ```julia
> function sortpermdim()
> 
> A = [ 1 5 3;
> 4 1 10]
> rev=false
> dims=1
> P = mapslices(x -> sortperm(x; rev = rev), A, dims = dims)
> # [1 2 1;
> # 2 1 2]
> indDim=ndims(P)
> sizeA=size(A)
> shape_ones = ones(Int64,indDim)
> 
> dest_dims = [collect(1:dims),missing,collect(dims+1:indDim)]
> 
> linIndeces = []
> for (dim, n) in (dest_dims, sizeA)
> if ismissing(dim)
> push!(linIndeces, indices)
> else
> 
> ind_shape = CartesianIndex(shape_ones[1:dim-1], sizeA[2] , shape_ones[dim+1:end])
> 
> push!(linIndeces,reshape([1:n],ind_shape))
> end
> return Tuple(linIndeces)
> 
> end
> end
> 
> ```

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [October 29, 2019, 10:53pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/4 "2019-10-29T22:53:27Z")

</div>

Ah, now I see why you posted in #dev. Perhaps we should move back there.

In any case, I don’t think we need to emulate what Numpy does here — we can do this much more efficiently. Something like what Tim posted ([https://github.com/JuliaLang/julia/issues/16273#issuecomment-228827130](https://github.com/JuliaLang/julia/issues/16273#issuecomment-228827130)) is a good start, but maybe we just want something like:

```julia
Base.sortperm(A; dims) = CartesianIndex.(Base.setindex(orthogonalaxes(A),mapslices(sortperm, A, dims=dims), dims)...)
orthogonalaxes(A) = ntuple(i->reshape(axes(A, i), ntuple(one, i-1)..., :), Val(ndims(A)))

```

In any case, we need to figure out if we want linear or Cartesian indices in the first place. Doing that in the issue itself is probably best.

---

<div class="post-metadata">

### Author: ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)
#### Post date: [October 29, 2019, 11:59pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/5 "2019-10-29T23:59:42Z")

</div>

Thanks for moving the thread.  
Let’s keep that `sortperm` discussion in the corresponding issue.

My issue is that if such thing (end keyword for CartesianIndex) can be implemented, why should we avoid it? If it isn’t straightforward, then I get the reason, and we need to work around it.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [October 30, 2019, 7:06am UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/6 "2019-10-30T07:06:38Z")

</div>

> [@Amin\_Yahyaabadi](#):
>
> if such thing (end keyword for CartesianIndex) can be implemented, why should we avoid it?

You don’t need consensus from others — nothing prevents you from starting a package to explore this.

As [explained above](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/2), if you want to perform deferred computation on this object, you would have to define pretty much all the algebra methods you consider relevant, and it still would not fit well into how indexing/slicing is implemented in Julia.

A workaround would be a closure, eg with something like

```julia
struct End{F}
    f::F
end

End() = End(identity)

function Base.to_indices(A, inds, I::Tuple{End, Vararg})
    (first(I).f(inds[1][end]), to_indices(A, Base.tail(inds), Base.tail(I))...)
end

```

which you would use as

```julia
A[End(i -> i + 1)]

```

but this does not take care of `:` etc.

I would recommend just adapting your coding style to Julia instead.

---

<div class="post-metadata">

### Author: ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)
#### Post date: [October 30, 2019, 9:15am UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/7 "2019-10-30T09:15:56Z")

</div>

Thank you for the answer. I think the type you defined is a good start and probably enough.

I didn’t know how to define this, that is why I am asking this here.

---

<div class="post-metadata">

### Author: ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)
#### Post date: [October 30, 2019, 7:30pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/8 "2019-10-30T19:30:23Z")

</div>

You can’t pack it in a `CartesianIndex`, but if you can work with a tuple here’s something like what you’re asking for:

```julia
julia> using EndpointRanges

julia> a = rand(3, 5)
3×5 Array{Float64,2}:
 0.415392 0.541634 0.720012 0.111273 0.831266  
 0.884652 0.186283 0.88156 0.843283 0.527316  
 0.166879 0.240574 0.0978097 0.899585 0.00569586

julia> a[iend-1, 2]
0.18628349057127114

julia> a[iend÷2, 2]
0.5416340535743596

```

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [October 30, 2019, 7:34pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/9 "2019-10-30T19:34:01Z")

</div>

Thank you Tim! It’s EndpointRanges that I was trying to remember above.

---

<div class="post-metadata">

### Author: ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)
#### Post date: [October 30, 2019, 7:34pm UTC](https://discourse.julialang.org/t/end-keyword-in-creating-cartesianindex/30461/10 "2019-10-30T19:34:06Z")

</div>

This is awesome. Thank you!
