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
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:
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
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.