Assert that 2D-Array never reduce to vector?

If I have a 2-D array A and idx is an index vector or value, and I want to assert that

A[idx,:]

be a 2D array (even if idx is a number), is there an easy way to do this without always having to divide into cases where idx is a list or idx is a number.

I have found a workaround which is to define a ‘safe’ script

s(x::Array{Int,1})=x
s(x::UnitRange{Int,1})=x
s(x::Int)=x:x
s(x::BitArray)=s(findall(x))

and the writing

A[s(idx),:]

This seems to work.

Is there a more elegant way? [e.g., explicitly asserting type of idx in a careful way such as:

idx :: Union{UnitRange{Int64},Array{Int64,1}}

]

I am of the opinion that usage of this should be easier than it is in Julia, but accept that I have obviously lost on that point. However, surely explicit assertion on a case-by-case basis should be possible (and allowed)?

Is there an easy way?

Thanks - If there were one single thing in Julia which I could honestly say has repeatedly caused me frustration in Julia (and which continues to prevent me from using Julia in my elementary classes) this would be it.

Thanks for any thoughts.

Maybe reshape?

julia> a = rand(2,3)
2×3 Array{Float64,2}:
 0.959615  0.457876  0.273112
 0.990784  0.980583  0.0332335

julia> atleast_2d(a) = reshape(a, axes(a,1), axes(a,2), axes(a)[3:end]...)
atleast_2d (generic function with 1 method)

julia> atleast_2d(a[1,:])
3×1 Array{Float64,2}:
 0.9596152547418273
 0.45787629350683146
 0.27311222755949016

julia> atleast_2d(a[1:1,:])
1×3 Array{Float64,2}:
 0.959615  0.457876  0.273112

julia> atleast_2d(a[(1:2) .> 1,:])
1×3 Array{Float64,2}:
 0.990784  0.980583  0.0332335

Do you require a[1,:] to be equal to a[1:1,:]?

1 Like

Thanks for that. The answer to your question is ‘yes’.

I guess what I would really hope for would be a new Type (perhaps only available locally) of Array which would automatically behave like this.
Almost as good would be a Vector Type which would never reduce to Int64
(as this could be used as an index).

No need for special cases, just write

s(x) = x
s(x::Integer) = x:x

(What is your reason for using findall on BitArray indices, btw?)

But, when do you get into problems like this? The type of the input index should normally be under control, so if indices are scalar, it should be easy for you to know this, and use

A[idx:idx, :]

Also, what do you want A[:, idx] to return, btw, for scalar idx? Do you want a vector or matrix?

1 Like

I missed this. This is what we have today. Vectors don’t reduce to scalars, so if you have a vector of length 1, it is still a vector and can be used to index the way you want.

1 Like

Thanks, that is simpler. If idx might be the result of a search, etc. then it could be vector or integer, in a way which might not be predicted beforehand.
If one has many lines like this in a script, making special cases for each is very clunky. At least the ‘safe index’ (s()) workaround, which you helpfully simplified, is quite a bit less clunky (and more readable as code).

Thanks!

This should not happen, and would constitute a type instability. Search functions that return vectors, always do that, so for example:

julia> findall(>(2), 1:4)
2-element Array{Int64,1}:
 3
 4

julia> findall(>(3), 1:4)
1-element Array{Int64,1}:
 4

julia> findall(>(4), 1:4)
Int64[]

It should always return a vector. Other functions like findfirst either return a scalar index or nothing.

If you have search functions that sometimes return one or the other, like you say, that should be fixed.

1 Like

BTW, I went and checked, and actually, numpy has the same behaviour here (except for the non-inclusive ranges):

In [18]: a = np.random.rand(5,5)                                                           

In [19]: a[3, :].shape                                                                     
Out[19]: (5,)

In [20]: a[:, 3].shape                                                                     
Out[20]: (5,)

In [22]: a[3:4, :].shape                                                                   
Out[22]: (1, 5)

In [23]: a[:, 3:4].shape                                                                   
Out[23]: (5, 1)

Matlab doesn’t have any vectors at all, so they are incapable of distinguishing (maybe my least favorite Matlab feature).

I don’t know about R.

What language do you use in the classes?

Thanks for that. I will have a look at my code. I’ll admit I had written my own wrapper for findall (with a calling syntax I find more convenient), but perhaps I
hadn’t seen this discrepancy between it and findall (which in any case, is easily fixable).

Thanks!

Thus far, I have used a combination of MATLAB, R, and Python, so switching to Julia would be handy. They come from a background which includes these 3, so I have been writing some ‘compatibility’ routines which make it easier for me. Maybe it is possible for me to make them work more consistently after all.

I have some problems grokking R, but it looks like it also does the same thing, and only Matlab does its own thing: Matrix | R Tutorial

Yeah, sounds like a nightmare trying to juggle all of them :grimacing: Transitioning would probably be good, but of course, not easy for everyone.

Fortunately, you can always ask questions here! Good luck!

I just implemented the changes which should cover the issues in most of the cases, and for those few issues which may not be covered, I now have a very simple ‘s()’ function above which will come in very handy!

Thanks again!