关于形状不可知的切片的ndarrays

kjo*_*kjo 13 matlab multidimensional-array

在这篇文章中,我使用的术语切片来指代一个子阵列B_i的的Ñ维阵列A,使得size(B_i, d)为1,对于一些尺寸d. Asize(A, d)这些切片组成,沿着维度连接d.

例如,如果ndims(A)是6并且d是3,那么表单的表达式

A(:, :, i, :, :, :)
Run Code Online (Sandbox Code Playgroud)

i1:size(A, d)代表所有片(沿维度d组成)A.

类似表达式的问题A(:, :, i, :, :, :)在于它不能象征性地概括为沿着与具有不同于6的维数的数组中的3的维度不同A的切片.例如,为了沿着维度2 获得切片,需要不同的表达式,A(:, i, :, :, :, :).这意味着这样的表达式在代码中是无用的,这些代码与要从中提取切片的某个数组的形状无关.

下面的函数是我的matlab-noob尝试实现与形状无关的切片.(这个名字slice已经被采用,因此我调用了函数hslice,简称为hyperslice.)函数的策略是将输入数组重新整形为一个合适的三维数组,沿着重新形成的数组的第二维获取所需的切片,并将结果重新整形为具有原始输入数组的切片形状.

function out = hslice(ndarray, d, i)
    sz = size(ndarray);
    pfx = sz(1:d-1);    % dimensions before d
    sfx = sz(d+1:end);  % dimensions after d

    tmp = reshape(ndarray, prod(pfx), sz(d), prod(sfx));
    out = reshape(tmp(:, i, :), [pfx 1 sfx]);
end
Run Code Online (Sandbox Code Playgroud)

是否有内置的,或至少更有效的方法来实现相同的结果(以形状无关的方式)?

And*_*nke 17

是啊.您可以使用解除引用的单元格数组和"逗号分隔列表"之间的等价,以及您可以使用char':'作为索引来动态构造A(:, :, :, i, :, ...)任意维度的调用.

function out = slice(A, ix, dim)

subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
out = A(subses{:});
Run Code Online (Sandbox Code Playgroud)

这将完全概括,并且将完成与原始静态A(:, :, i, :, ...)表达式完全相同的"切片"索引操作,除了将这些字符串设置为错误的开销.

或者如果你想,你可以用它sprintf来构造A(:, :, i, :, ...)一个字符串,然后调用eval()它.但我想尽可能避免eval.

请注意,您的原始实现正在使用快速操作,并且应该执行得很好,与此速度一样快.我只是张贴这个,因为我认为它非常易读,可以回答你最初提出的问题,并且它可以应用于其他有用的东西.

对切​​片的分配

您还可以使用相同的下标单元格技术作为左值来分配数组的切片.但是,您不能直接重用切片函数,因为它返回数组的提取子集,而不是左值引用.所以你可以创建一个非常相似的函数来完成赋值本身.

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;
Run Code Online (Sandbox Code Playgroud)

在实践中,您可能还需要一个只返回单元数组中计算索引的函数,因此您可以携带它们并重复使用它们进行赋值和引用.

function out = slice_subs(A, ix, dim)

subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
out = subses;
Run Code Online (Sandbox Code Playgroud)

  • 谁知道你可以做'A(':',':',2,':')`?我只想重申这个想法有多酷. (4认同)