Does Cartesian Indexing work on single values?

My goal is to create a function to check if my data points are valid, i.e., not an NaN and not equal to -999.

Here is the function I wrote:
f(A) = [idx for idx in CartesianIndices(A) if @inbounds (!isnan(A[idx]) && A[idx] != -999)];

Why does it work on vector data like N1 but not on single values like N2?

N1 = [3.7, 4.5];
N2 = 3.7;

How do I make it work for single values as well?

Thanks!

There’s no sensible way to assign a Cartesian index to a floating-point value, so Julia doesn’t implement the associated method:

julia> CartesianIndices(3.7)
ERROR: MethodError: no method matching CartesianIndices(::Float64)
Closest candidates are:
  CartesianIndices(::CartesianIndex) at C:\Users\alexa\.julia\juliaup\julia-1.7.1+0~x64\share\julia\base\multidimensional.jl:276
  CartesianIndices(::AbstractArray) at C:\Users\alexa\.julia\juliaup\julia-1.7.1+0~x64\share\julia\base\multidimensional.jl:280
  CartesianIndices(::Tuple{}) at C:\Users\alexa\.julia\juliaup\julia-1.7.1+0~x64\share\julia\base\multidimensional.jl:270
  ...
Stacktrace:
 [1] top-level scope
   @ REPL[20]:1

You probably want to use the built-in function findall instead:

julia> f(A) = findall(A) do Aᵢ
           !isnan(Aᵢ) && Aᵢ != -999
       end
f (generic function with 1 method)

julia> f([3.7, 4.5])
2-element Vector{Int64}:
 1
 2

julia> f(3.7)
1-element Vector{Int64}:
 1
2 Likes

Thanks for the reply.

That’s so bad. Cartesian index is one of the fastest ways to process large amounts of data.

You probably want eachindex here anyway instead of CartesianIndices?

julia> f(A) = [idx for idx in eachindex(A) if @inbounds (!isnan(A[idx]) && A[idx] != -999)]
f (generic function with 1 method)

julia> N1 = [3.7, 4.5];

julia> N2 = 3.7;

julia> f(N1)
2-element Vector{Int64}:
 1
 2

julia> f(N2)
1-element Vector{Int64}:
 1

Or do you require the Cartesian indices in particular?

2 Likes

I just realize that it does not work either. Here is why:

YES(A) = [idx for idx in eachindex(A) if @inbounds (!isnan(A[idx]) && A[idx] != -999)];
N2 = 3.7
Ind = YES(N2)

N2[Ind] will give me the below error:

ERROR: MethodError: no method matching getindex(::Float64, ::Vector{Int64})
Closest candidates are:
  getindex(::Number) at /Applications/Julia-1.7.app/Contents/Resources/julia/share/julia/base/number.jl:95
  getindex(::Union{AbstractChar, Number}, ::CartesianIndex{0}) at /Applications/Julia-1.7.app/Contents/Resources/julia/share/julia/base/multidimensional.jl:831
  getindex(::Number, ::Integer) at /Applications/Julia-1.7.app/Contents/Resources/julia/share/julia/base/number.jl:96
  ...
Stacktrace:
 [1] top-level scope

This seems to be a Julia bug to me. I mean, no indexing system should fail only because the vector is reduced down to just 1 value.

N2[Ind...] to get a scalar index, or encapsulate the scalar in a container: [N2][Ind]

1 Like

Do I have to write a loop so that my program will treat a scalar differently from a vector? It seems Julia wants to make something really simple really complex.

This thread is a bit odd, your scalars should probably be 1-element vectors for type stability, and then CartesianIndex would work too.

2 Likes

Thanks! The values are generated out of an external program.

Is there a universal function to convert either a scalar, or a 1-column data, or a vector to a vector?

I tried vec(), and it does not work for scalars.

[x;] works for both vectors and scalars.

1 Like

Excellent! Many thanks

Sure there is. Julia treats numbers (and characters) as 0-dimensional arrays:

julia> x = 3.7
3.7

julia> x[]
3.7

julia> x[CartesianIndex()]
3.7

so it would make sense to have something like:

CartesianIndices(::Union{Number,AbstractChar}) = CartesianIndex():CartesianIndex()
3 Likes

This gets a bit unintuitive with Julia’s multidimensional getindex behavior:

julia> 1[]
1

julia> 1[CartesianIndex()]
1

julia> 1[1, 1]
1

julia> 1[CartesianIndex(1, 1)]
ERROR: MethodError: no method matching getindex(::Int64, ::CartesianIndex{2})
[...]
1 Like

That seems like a separate issue — a missing getindex method (for consistency…I’m not sure how useful it is).

Julia has treated numbers as 0-dimensional arrays for years now and we long ago decided to keep it (make numbers non-iterable? · Issue #7903 · JuliaLang/julia · GitHub), so it seems like CartesianIndices should be consistent with that…

3 Likes