On shape-agnostic slicing of ndarrays

Yeah. You can use the equivalence between dereferenced cell arrays and “comma-separated lists”, and the fact that you can use a char ‘:’ as an index to dynamically construct that A(:, :, :, i, :, ...) invocation for arbitrary dimensions.

function out = slice(A, ix, dim)

subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
out = A(subses{:});

This will generalize fully, and will do exactly the same “slice” indexing operation as the original static A(:, :, i, :, ...) expression, aside from the overhead of twiddling those strings to set it up.

Or if you wanted to, you could just use sprintf to construct that A(:, :, i, :, ...) as a string and then call eval() on it. But I like to avoid eval if at all possible.

Note that your original implementation is using fast operations and should perform just fine, about as fast as this one. I’m just posting this because I think it’s very readable, does answer your question as originally posed, and it could be applied to other useful stuff.

Assignment to Slices

You can also use this same subscripts-in-a-cell technique as an lvalue to assign in to slices of an array. You can’t reuse the slice function directly, though, since it returns an extracted subset of the array, and not an lvalue reference. So you can make a very similar function that does the assignment itself.

function A = slice_assign(A, ix, dim, B)
%SLICE_ASSIGN Assign new values to a "slice" of A

subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
A(subses{:}) = B;

In practice, you might also want a function that just returns the computed indexes in a cell array, so you could carry those around and use them repeatedly for assignment and referencing.

function out = slice_subs(A, ix, dim)

subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
out = subses;

Leave a Comment