# PSA: replacement of ind2sub/sub2ind in Julia 0.7+

**URL:** <https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666>\
**Category:** General Usage\
**Tags:** indexing\
**Created:** [September 7, 2018, 3:19pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666 "2018-09-07T15:19:07Z")\
**Posts on this page:** 16\
**Page:** 2

<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 26, 2019, 3:22am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/21 "2019-01-26T03:22:30Z")

</div>

Or even simpler (I think; untested):

```julia
ind2subv(shape, indices) = Tuple.(CartesianIndices(shape)[indices])
sub2indv(shape, indices) = LinearIndices(shape)[CartesianIndex.(indices)]

```

---

<div class="post-metadata">

**Author:** ![jebej](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jebej/32/1784_2.png) [@jebej](https://discourse.julialang.org/u/jebej)\
**Post date:** [January 26, 2019, 4:30am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/22 "2019-01-26T04:30:01Z")

</div>

Or even easier:

```julia
Base._ind2sub
Base._sub2ind

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 26, 2019, 8:49am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/23 "2019-01-26T08:49:13Z")

</div>

> [@murphyk](#):
>
> Some matlab users might be familar with ind2subv and subv2ind

But the point of `CartesianIndex` etc. is that it’s _better_ than the Matlab approach. Reimplementing Matlab functionality to avoid using idiomatic Julia seems counterproductive. What’s the gain?

---

<div class="post-metadata">

**Author:** ![murphyk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/murphyk/32/6891_2.png) [@murphyk](https://discourse.julialang.org/u/murphyk)\
**Post date:** [January 26, 2019, 4:11pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/24 "2019-01-26T16:11:17Z")

</div>

I agree the Julia approach is better. My functions are not meant as a replacement, but instead as a lightweight wrapper around the Julia methods, to provide the functionality illustrated below:

ind2subv( (3,4,2), [3,5]) = [(3, 1, 1), (1, 2, 1)]

subv2ind( (3,4,2), [(3,1,1), (1,2,1)]) = [3, 5]

This is useful for applications such as discrete graphical models. As I learn more Julia, maybe I’ll discover a more “Julianic” way to do it without using these wrappers. (BTW, I agree the function names are terrible, and are just meant to help me port my legacy matlab code, but I may change them to lin2cart and cart2lin or something like that.)

---

<div class="post-metadata">

**Author:** ![murphyk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/murphyk/32/6891_2.png) [@murphyk](https://discourse.julialang.org/u/murphyk)\
**Post date:** [January 26, 2019, 4:52pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/25 "2019-01-26T16:52:37Z")

</div>

Yes, this works great!

I even wrote the “dual” of it in your style.

function cart2lin(shape, cindices)

lndx = LinearIndices(Dims(shape))

return getindex.(Ref(lndx), cindices)

end

However, it’s a pain to have to manually wrap tuples inside the CartesianIndex contructor.

I’d like to pass in a vector of tuples, as in cart2lin([3,4,2],[(3,1,1), (2,2,1)]),

and have it convert my arguments automatically. I can do this as follows:

function tuple2lin(shape, indices)

lndx = LinearIndices(Dims(shape))

cindices = [CartesianIndex(i) for i in indices]

return getindex.(Ref(lndx), cindices)

end

but I just want to write one function, and depending on the type of the “indices” argument,

convertng from Array{Tuple} to Array{CartesianIndex} if necessary.

I tried writing 2 function signatures but it does not work (always calls the first one even if I pass

in an array of tuples). What am I missing?

function cart2lin(shape::Tuple, cindices::Array{CartesianIndex})…

function cart2lin(shape::Tuple, indices::Array{Tuple}) # == tuple2lin

---

<div class="post-metadata">

**Author:** ![murphyk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/murphyk/32/6891_2.png) [@murphyk](https://discourse.julialang.org/u/murphyk)\
**Post date:** [January 26, 2019, 6:12pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/26 "2019-01-26T18:12:24Z")

</div>

Sorry, I think my last email was unclear. What I would like to do is to have Julia dispatch to either cart2lin or tuple2lin, depending on the type of the second argument. How do I do this?

function cart2lin(shape, cindices)

lndx = LinearIndices(Dims(shape))

return getindex.(Ref(lndx), cindices)

end

function tuple2lin(shape, indices)

cindices = [CartesianIndex(i) for i in indices]

return cart2lin(cindices)

end

function test()

shape = (3,4,2)

cndx = [CartesianIndex(3,1,1), CartesianIndex(2,2,1)]

lndx = cart2lin(shape, cndx)

@assert lndx == [3,5]

ndx = [(3,1,1), (2,2,1)]

lndx = tuple2lin(shape, ndx)

@assert lndx == [3,5]

shapes = [(3,4,2), (4,1,5,2)]

for shape in shapes

K = prod(shape)

subs = ind2subv(shape, 1:K)

ndx = subv2ind(shape, subs)

@assert ndx == 1:K

end

end

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 26, 2019, 6:17pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/27 "2019-01-26T18:17:20Z")

</div>

Do you think you can wrap your code in triple backticks and indent properly, like you did in your first post? This is really hard to read.

---

<div class="post-metadata">

**Author:** ![jekbradbury](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jekbradbury/32/953_2.png) [@jekbradbury](https://discourse.julialang.org/u/jekbradbury)\
**Post date:** [January 26, 2019, 9:18pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/28 "2019-01-26T21:18:11Z")

</div>

Because `CartesianIndex(cidx::CartesianIndex) = cidx` (this is often true for wrapper types), @mbauman’s suggestion should do what you want for both tuples and `CartesianIndex`es. I just tested this code:

```julia
ind2subv(shape, indices) = Tuple.(CartesianIndices(shape)[indices])
sub2indv(shape, indices) = LinearIndices(shape)[CartesianIndex.(indices)]

function test()
  shape = (3, 4, 2)
  cndx = [CartesianIndex(3, 1, 1), CartesianIndex(2, 2, 1)]
  lndx = sub2indv(shape, cndx)
  @assert lndx == [3, 5]
  ndx = [(3, 1, 1), (2, 2, 1)]
  lndx = sub2indv(shape, ndx)
  @assert lndx == [3, 5]
  shapes = [(3,4,2), (4,1,5,2)]
  for shape in shapes
    K = prod(shape)
    subs = ind2subv(shape, 1:K)
    ndx = sub2indv(shape, subs)
    @assert ndx == 1:K
  end
end

```

---

<div class="post-metadata">

**Author:** ![murphyk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/murphyk/32/6891_2.png) [@murphyk](https://discourse.julialang.org/u/murphyk)\
**Post date:** [January 27, 2019, 4:02am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/29 "2019-01-27T04:02:47Z")

</div>

You guys rock! Thanks a lot. I’m pasting the final solution below for posterity.  
(Both versions work.)

```nohighlight
    """
    Transform linear indices to cartesian, cf ind2subv.
    Example:
    lin2cart((3,4,2), [3,5]) = [(3, 1, 1), (2, 2, 1)]
    """
    #https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/20
    #return Tuple.(CartesianIndices(shape)[indices])
    return [Base._ind2sub(shape, i) for i in indices]
end

function cart2lin(shape, indices)
    """
    Transform vector of cartesian indices to linear indices, cf subv2ind.
    Example:
    cart2lin([3,4,2], [(3,1,1), (2,2,1)]) = [3, 5]
    """
    #https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/20
    #return LinearIndices(shape)[CartesianIndex.(indices)]
    return [Base._sub2ind(shape, i...) for i in indices]
end
```

---

<div class="post-metadata">

**Author:** ![murphyk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/murphyk/32/6891_2.png) [@murphyk](https://discourse.julialang.org/u/murphyk)\
**Post date:** [January 27, 2019, 4:05am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/30 "2019-01-27T04:05:54Z")

</div>

Whoops, first function got cut off. Sorry, trying one more time.

```julia
function lin2cart(shape, indices)
    """
    Transform linear indices to cartesian, cf ind2subv.
    Example:
    lin2cart((3,4,2), [3,5]) = [(3, 1, 1), (2, 2, 1)]
    """
    #https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/20
    #return Tuple.(CartesianIndices(shape)[indices])
    return [Base._ind2sub(shape, i) for i in indices]
end

function cart2lin(shape, indices)
    """
    Transform vector of cartesian indices to linear indices, cf subv2ind.
    Example:
    cart2lin([3,4,2], [(3,1,1), (2,2,1)]) = [3, 5]
    """
    #https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/20
    #return LinearIndices(shape)[CartesianIndex.(indices)]
    return [Base._sub2ind(shape, i...) for i in indices]
end
```

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [January 27, 2019, 7:02am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/31 "2019-01-27T07:02:45Z")

</div>

Glad you found a solution! Two recommendations:

I would not use the underscored functions (`_ind2sub` and `_sub2ind`) if I didn’t have to. They are internal functions that could have their functionality changed or be removed in a future version of Julia. They are also undocumented, so people reading your code can’t easily search for these functions to see what they’re doing.

You could also move the documentation to just above each function (not inside the function). That way they will be proper docstrings and available in Julia’s help mode. [See details here](https://docs.julialang.org/en/latest/manual/documentation/index.html).

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 27, 2019, 9:38am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/32 "2019-01-27T09:38:27Z")

</div>

> [@murphyk](#):
>
> Whoops, first function got cut off. Sorry, trying one more time.

It’s also possible to edit the post with the missing code.

Are you perhaps reading this through an email client? I ask because you seemed previously to reply to a remark that I had deleted, due to a misunderstanding, and referring to a post as an email. As far as I know quite a few posters do that, but it could occasionally lead to some confusion.

If you use the web-interface, you can fix typos, add code formatting (which is missing in some of your posts), and fix other mistakes without having to repost all the contents. You can also delete posts entirely.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 27, 2019, 9:26pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/33 "2019-01-27T21:26:46Z")

</div>

> [@tim.holy](#):
>
> The [blog post](https://julialang.org/blog/2016/02/iteration) has now been updated

I’ve read this very interesting blog post, and came away thoroughly impressed with the ease and power of `CartesianIndex`/`ices`. There is just one thing bothering me, and that is the behaviour of `max`. According to the docs:

```julia
help?> max
[...]
Return the maximum of the arguments.

```

However,

```julia
julia> max(CartesianIndex(0, 1), CartesianIndex(1, 0))
CartesianIndex(1, 1)

```

doesn’t return the max of the two arguments (that is, return _either_ the first _or_ the second argument), but something in between. Compare this to

```julia
julia> max((0, 1), (1, 0))
(1, 0)

julia> max.((0, 1), (1, 0))
(1, 1)

```

Since “a CartesianIndex has to be viewed as a single (scalar) entity, rather than as a container in its own right”, I find this a bit hard to reconcile. `max` of two index’es behaves more as if it’s been broadcasted over two containers.

Is `max` the right name for this operation? Or should perhaps the docstring of `max` be tweaked? Alternatively, how can I get a good intuition about how this works?

---

<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, 2019, 2:27pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/34 "2019-01-28T14:27:06Z")

</div>

That’s worth opening an issue for dedicated discussion.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 29, 2019, 7:59am UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/35 "2019-01-29T07:59:39Z")

</div>

Do you mean a github issue, or a separate thread on discourse?

---

<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, 2019, 5:11pm UTC](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666/36 "2019-01-29T17:11:20Z")

</div>

A GitHub issue.

[Previous page](https://discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666.md?page=1)
