Way to slice an array of unknown number of dimensions?

This might be naive, but I couldn’t find an answer else where:

Let A be an Nd-array, where Nd is unknown exactly till runtime, e.g., only sure that Nd>=3.
Is there a good way to slice it along, e.g., the n<=3th dimension?

For comparison, in numpy, one can do:

>>> A = numpy.ones((3,3,3,3));
>>> A[1,:]
array([[[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]],
       [[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]],
       [[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]]])

This made things each for me, as the slice is shape-ready for broadcasting operations on A afterwards.

Thanks.

3 Likes

I think with constant folding, you could construct an argument to the API of this package that would be type stable.

There is also EllipsisNotation.jl. Also see https://github.com/JuliaLang/julia/issues/5405.

2 Likes

Thanks! I will check out those modules.

So I guess, for ≤ v1.1, it’s yet a missing feature.

More like <= v1.3.

You can also just use selectdim for this. For your case

julia> A=ones(3,3,3,3);

julia> selectdim(A, 1, 1)
3×3×3 view(::Array{Float64,4}, 1, :, :, :) with eltype Float64:
[:, :, 1] =
 1.0  1.0  1.0
 1.0  1.0  1.0
 1.0  1.0  1.0

[:, :, 2] =
 1.0  1.0  1.0
 1.0  1.0  1.0
 1.0  1.0  1.0

[:, :, 3] =
 1.0  1.0  1.0
 1.0  1.0  1.0
 1.0  1.0  1.0

selects the first slice along the first dimension.

7 Likes

That actually works very well for me!
Thanks!


A few more comments for future readers.

Played with selectdim for a little. selectdim is smooth for r-value, (retrieve).
For l-value, (assign), one need copyto!(selectdim(...), new_val), etc.

IMHO, it’s a bit more of a workaround, than the feature wanted, A[1, ..] (syntax sugar provided in EllipsisNotation).


See @simeonschaub 's reply for a better way of using selectdim as l-value. (not copyto!)

Have you tried selectdim(A, 1, 1) .= new_val?

ah, I see, thanks for that!
That feels a bit tricky, I thought same sized array copy would go smooth through =.

I think it makes sense that you need .=. If you type selectdim(A, 1, 1) = new_val then Julia interprets this as a function definition, i.e., Julia thinks you are trying to make a function called selectdim with arguments A, 1, and 1 that returns new_val. But 1 is an invalid argument name, hence the error ERROR: syntax: "1" is not a valid function argument name. (On the other hand, selectdim(A, d, i) = new_val would quietly create a function that accepts 3 arguments and always returns new_val.)

Additionally, selectdim(...) returns an object, and it doesn’t make sense to assign an object to a value, just as 1 = 2 doesn’t make sense.

Agreed, it just feels a bit extra mind work to me, especially when I had p=selecdim(...), then, few lines later, having p.=c:
“wait, why do I need an element-wise assignment here between two same sized variable…, oh…, it’s a view and = doesn’t go through”.
Probably I am just not used to view, and expected pointer-like behavior from it…

The key isn’t the view, it’s the difference between A = X, A[I] = X and A .= X.

The first just creates a new name — an alias — for X. The second updates an existing A at the given indices to contain X. The third updates all indices of an existing A to contain X. All three of these forms are special syntaxes. This includes the second one — “indexed assignment” — so pulling out the indexing away from the = will mean something different.

You can use views in the latter two expressions to further restrict the indices. But you cannot use views in the first one because it’s not doing any updating at all!

3 Likes

Thanks a lot!
It is very helpful knowing that A=X is creating an alias. I wish this clarification could be in the doc.

As discussed multiple times here (search the forum), calling it an alias is not helpful.

Generally, code like

A = X

simply makes A and X have the same value, in the sense that A === X, ie (quoting from ?===)

in the sense that no program could distinguish them

This applies to all kinds of values: integers, strings, and arrays. For arrays, neither is an an alias of the other, they are the same. Consequently, for a function like

f(Z) = (Z[1] = 2; nothing)

both f(A) and f(X) after A = X should just modify the same array, otherwise a program could distinguish them.

It’s an alias in the sense of normal English language alias. Like how the FBI would use the word alias. For some folks that’s what makes it click. For others it does indeed just muddy the waters based upon how they’ve used “aliasing” in the context of computer languages. Perhaps when I use that word I should clarify it’s the FBI’s alias — just two names for the same thing.

This is where I find more confusion — I think it’s easier to say that A and X don’t have or hold values, they’re just names. That’s it.

As always with mental models and teaching, your mileage may vary.

1 Like

If you prefer that usage, you can say that after A = X, A and X are variables that refer to the same value.

Sorry, since I don’t follow criminal news of the US I am not sure how the FBI uses aliases.

I just think the term is misleading if it suggests that one of those variables is “the original” or is distinguished in some sense. I find that this interpretation is quite common when people talk about aliases.