Change a vector CartesianIndex

I was wondering if I could get help with this problem.
I have a matrix and find every index where its value is negative.

mat = [1 2 3 ; -1 -2 3]

ind = findall(<(0),mat)

2-element Vector{CartesianIndex{2}}:
 CartesianIndex(2, 1)
 CartesianIndex(2, 2)

Something I want to do is to change the row before each CartesianIndex; CartesianIndex(1,1), CartesianIndex(1,2). I tried to following

function ind_ready(;ind = ind)
        
    A = hcat(getindex.(ind,1),getindex.(ind,2))
    A[:,1] = A[:,1] .- 1   
    B = Any[]
    C = CartesianIndex[] 

    for i in 1:length(ind) 
        B = push!(B,(A[i,1],A[i,2]))
    end


    for i in 1:length(B) 
        C = push!(C,CartesianIndex(B[i]))
    end

    return C

end

Then I get the following

2-element Vector{CartesianIndex}:
 CartesianIndex(1, 1)
 CartesianIndex(1, 2)

However, with this

mat[ind_ready()]

returns the following error

ArgumentError: unable to check bounds for indices of type CartesianIndex{2}

How can I fix this problem?

Any suggestion would be greatly helpful.

ind .= CartesianIndex.(getindex.(ind, 1) .- 1, getindex.(ind, 2))

or equivalently

@. ind = CartesianIndex(getindex(ind, 1) - 1, getindex(ind, 2))

which gives

julia> mat[ind]
2-element Vector{Int64}:
 1
 2

Two problems: your ind_ready() function actually decrements the second index (with A[:,2] = A[:,2] .- 1 ), not the first, resulting in invalid 0 indices:

julia> i2 = ind_ready()
2-element Vector{CartesianIndex}:
 CartesianIndex(2, 0)
 CartesianIndex(2, 1)

Second, Julia doesn’t like that your ind_ready returns an abstractly typed CartesianIndex[] vector and not a concretely typed CartesianIndex{2}[] vector:

julia> mat[CartesianIndex[CartesianIndex(1,1)]]
ERROR: ArgumentError: unable to check bounds for indices of type CartesianIndex{2}

julia> mat[CartesianIndex{2}[CartesianIndex(1,1)]]
1-element Vector{Int64}:
 1

But this error message is confusing and should be fixed: confusing error for array[CartesianIndex[...]] indexing · Issue #48655 · JuliaLang/julia · GitHub

You could simply do:

ind .-= Ref(CartesianIndex(1,0))
mat[ind]

Oh, right, I forgot that CartesianIndex supports vector operations (± and multiplication by scalars).

Thank you very much!

I figured out that my example has the problem you mentioned, so I changed the example to a row. I’ll edit the code in the question accordingly.

I was just wondering one more thing. Is there a way that I can put conditions? I want to reduce by one if the cartesian index is bigger than one?

Thank you so much. Now I can cut my messy codes into half :slight_smile:

Yes, of course. One solution would be to include a call to max (or ifelse or similar):

ind .= CartesianIndex.(max.(1, getindex.(ind, 1) .- 1), getindex.(ind, 2))

but when things become sufficiently complicated at some point it becomes clearer to write an “scalar” expression that does what you want, and either broadcast it or use a comprehension or map. For example, one of:

newind = map!(ind) do c
    CartesianIndex(max(1, c[1]), c[2])
end

map!(ind, ind) do c
    CartesianIndex(max(1, c[1]), c[2])
end

newind = [CartesianIndex(max(1, c[1]), c[2]) for c in ind]

f(c) = CartesianIndex(max(1, c[1]), c[2])
ind .= f.(c)

ind .= (c -> CartesianIndex(max(1, c[1]), c[2])).(ind)

and of course once you write it like this you can use if statements or whatever you want to transform c.

If your need is to handle cases where some negative value is in the first row, you could make use of a variant of @rafael.guerra solution


mat3 = [-2 -3 4; 1 2 3 ; -1 -2 3]

ind3 = findall(<(0),mat3)

ind3 .-= Ref(CartesianIndex(1,0))

nind=[i - CartesianIndex(1,0) for i in ind3 if i.I[1] > 1]

I thank all of you so much !