# Converting cartesian index to what it would be in view

**URL:** <https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310>\
**Category:** General Usage\
**Tags:** cartesianindices\
**Created:** [January 28, 2026, 3:45pm UTC](https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310 "2026-01-28T15:45:24Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [January 28, 2026, 3:45pm UTC](https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310/1 "2026-01-28T15:45:24Z")

</div>

Suppose we have

```julia-auto
a = CartesianIndices((3,3))
b = a[2:3, :] 

indx = CartesianIndex((3,3)) 
map_index_to_what_it_would_be_in_slice(?, indx::CartesianIndex) = ? 

using Test
@test a[indx] == b[map_index_to_what_it_would_be_in_slice(?, indx)] 

```

So, `CartesianIndex((3,3))` is in `b` located at `CartesianIndex(3,2)`.  
I want the most efficient way to convert `CartesianIndex((3,3))` to `CartesianIndex((3,2))`.

What I am asking for is sort of the reverse of what view does under the hood.

There are lots of ways to do this (findfirst, modular arithmetic) but I want the most performant one and preferably one that is already supported in Base. I would like this to work with arbitrary slicing of a CartesianIndices array (e.g. `other_b = a[[1,3], 1]`. Are there existing functions in Base to accomplish this? If not, what is the most performant approach?

Motivation: I am trying to write a higher-dimensional sparse array type that avoids using dictionaries (like SparseArrayKit does) and is faster for certain operations. Indeed, what little I have written is faster at what I need to to be faster at. But, to make my type satisfy standard array interfaces, I want to allow these arrays to be sliced (`my_cartesian_sparse_array[1, :, :]`) and returned as my sparse array type. Because my sparse array type stores a `Vector{<:CartesianIndex}` to keep track of non-sparse positions, I need to be able to map each in a subset of CartesianIndex to a new CartesianIndex corresponding with position in the sliced array.

---

<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:** [January 28, 2026, 4:53pm UTC](https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310/2 "2026-01-28T16:53:37Z")

</div>

That’s arithmetic, no?

```julia-auto
julia> CartesianIndex((3,3)) - CartesianIndex((0,1))
CartesianIndex(3, 2)

```

If you have a vector of `CartesianIndex`, you can broadcast the arithmetic or do something lazy. I don’t think you’d be able to directly re-use Base’s `view` machinery to do that lazy thing, because that’s built upon the cartesian _products_ and it works upon each dimension independently, working with the _rectangular_ subsets.

Just in the off-chance that you aren’t aware, it sounds like you’ve implemented a COO sparse format. I think a number of folks have also implemented such things.

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [January 29, 2026, 8:43pm UTC](https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310/3 "2026-01-29T20:43:56Z")

</div>

Thank you for the reply, but the problem is more general.

Suppose instead we had

```julia-auto
# For 
    c = CartesianIndices((2,3,4)) # or some other (2, 3, 4) sized AbstractArray
    vc = view(c, 2, 2:3, [1,3])
# we have that 
    vc[2,2] == CartesianIndex(2, 3, 3)
# so, the view function maps the indexing argument CartesianIndex(2,2) to the indexing argument CartesianIndex(1,3,3) for c 

We want the reverse: 
    ReverseViewIndexing(c, 2, 2:3, [1,3])(1, 3, 3) == CartesianIndex(2, 2)
    ReverseViewIndexing(c, 2, 2:3, [1,3])(1, 3, 5) == CartesianIndex(2, 3)
    ReverseViewIndexing(c, 2, 2:3, [1,3])(1, 3, 4) == nothing # or maybe throws error 
    ReverseViewIndexing(c, 2, 2:3, [1,3])(2, 3, 3) == nothing # or maybe throws error 

# for arbitrary indexing of arbitrary arrays, the general equivalence is
view(arr, view_indx...)[other_indx...] == 
    arr[ReverseViewIndexing(c, view_indx...)(other_indx...)]

```

It seems like there are a lot of special cases depending on what sort of arguments are passed to view.

In addition, it seems like some implementation approaches might be faster for certain applications, such as when applying

```julia-auto
indxs::Vector{CartesianIndex{D}} 
ReverseViewIndexing(x, view_indx...)(indxs) 

```

to a large vector of CartesianIndex if its elements are sorted, unique, etc…

This seems like a problem where a solution is probably already out there.

I think I’m overthinking it and it may just be a couple of helper functions to handle the various special cases.

Also,

> Just in the off-chance that you aren’t aware, it sounds like you’ve implemented a COO sparse format.

I was unaware. Thank you for pointing this out. However, the couple of Julia packages I was able to find use COO format only for vectors and Matrices, and my motivation is for higher-dimensional arrays (otherwise I would be content with SparseMatrixCSC). Is there a particular package you would recommend?

---

<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:** [January 29, 2026, 9:32pm UTC](https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310/4 "2026-01-29T21:32:33Z")

</div>

I mean, the general case is precisely what powers Base’s `view` — you just [index into the indices](https://github.com/JuliaLang/julia/blob/9922b9fa5451d51a848203c936f3b9778447773f/base/subarray.jl#L274-L304) themselves! But as I understand it, you really don’t want something general; you want your special sparse optimizations, and more importantly, something that can easily use the methods with those sparse optimizations you’ve already built.

One option is to just let `view` do its thing, and enable dispatch on `SubArray{T, N, <: YourMultidimensionalSparseCOO, <: FastIndexTypes}`, with special methods that compute those indices on demand for those subset of `FastIndexTypes` for which you can do so.

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [January 29, 2026, 10:37pm UTC](https://discourse.julialang.org/t/converting-cartesian-index-to-what-it-would-be-in-view/135310/5 "2026-01-29T22:37:01Z")

</div>

> you just [index into the indices](https://github.com/JuliaLang/julia/blob/9922b9fa5451d51a848203c936f3b9778447773f/base/subarray.jl#L274-L304) themselves!

It’s really cool! But I need the reverse of that functionality.

This is what I implemented:

```julia-auto
using Test 

revslice(s::I) where I <: Integer = nothing   
revslice(r::Union{AbstractRange, AbstractVector{<:Integer}}) = (rs = zeros(Int64, maximum(r)); rs[r] .= 1:length(r); rs)
revslice(r::Union{BitVector, AbstractVector{<:Bool}}) = (rs = zeros(Int64, length(r)); rs[r] .= 1:sum(r); rs)

struct RevViewCart{DF, DT, TS}
    apply_to::Vector{Bool}
    revslices::TS 
end 
function RevViewCart(DF::Int, DT::Int, slices_tuple::Tuple)
    revslices = revslice.(slices_tuple) 
    apply_to = [.!isnothing.(revslices)...]
    revslices = revslices[apply_to]
    RevViewCart{DF, DT, typeof(revslices)}(apply_to, revslices)
end 
RevViewCart(v::SubArray) = RevViewCart(length(size(v.parent)), length(size(v)), v.indices)
        

function (rvc::RevViewCart{DF, DT, TS})(from_cart::CartesianIndex{DF})::CartesianIndex{DT} where {DF, DT, TS} 
    return CartesianIndex(getindex.(rvc.revslices, from_cart.I[rvc.apply_to]))
end 
(rvc::RevViewCart)(args::Vararg{Integer}) = rvc(CartesianIndex(args))
    
c = CartesianIndices((2,3,4)) 
vc = view(c, 2, 2:3, [1,3])
rvc = RevViewCart(vc)
@test rvc(1,3,1) == CartesianIndex(2,1)
@test rvc(1,3,3) == CartesianIndex(2,2)
@test rvc(1,2,1) == CartesianIndex(1,1)
@test rvc(1,2,3) == CartesianIndex(1,2)

```

> One option is to just let `view` do its thing, and enable dispatch on `SubArray{T, N, <: YourMultidimensionalSparseCOO, <: FastIndexTypes}` , with special methods that compute those indices on demand for those subset of"

Well, I want getindex calls or collect(::SubArray{MyType}) to be able to return the same Sparse Array type and not default to a dense array. Doing so requires reindexing, which is what the function I am asking about accomplishes. Many times the miracles of multiple dispatch results some in a hidden getindex call converting by default to the default dense Array type, which would entail allocating memory until the computer runs out of memory. Not fun.

BTW similar problems happen with SparseMatrixCSC, where broadcast division of a sparse matrix by a column of a sparse matrix (if I recall correctly) will return a sparse matrix – but with with no sparsity. ctrl+c ctrl+c ctrl+c

But yes, using views is great and I will remember your suggestion. In particular the fancy Base.tail trick used by views looks useful. Julia is a wonderful language and the community is great.
