在形状不可知论的切片的ndarrays
在这篇文章中,我使用术语slice来指代n维数组A
的子阵B_i
,使得对于某个维d
, size(B_i, d)
是1。 A
由size(A, d)
这样的切片组成,沿着维度d
连接。
例如,如果ndims(A)
是6, d
是3,那么表单的expression式
A(:, :, i, :, :, :)
对于i
in 1:size(A, d)
表示构成1:size(A, d)
所有切片(沿着维度d
)。
像A(:, :, i, :, :, :)
这样的expression式的问题在于它不能像一个维数不等于6的数组那样, A
的切片沿维度2,需要一个不同的expression式A(:, i, :, :, :, :)
。 这意味着这样的expression式在代码中是无用的,这些代码对于从中提取片段的某个数组的形状是不可知的。
下面的函数是我的matlab-noob试图实现形状不可知的切片。 (名称slice
已经被占用,因此我称之为函数hslice
,简称为hyperslice
。该函数的策略是将input数组重新整形为一个合适的三维数组,然后沿着重构数组的第二维取出所需的片,然后重新整形从原始input数组中得到具有切片形状的结果。
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
是否有内置或至less更高效的方式来实现相同的结果(以与形状无关的方式)?
是啊。 您可以使用取消引用的单元格数组和“逗号分隔列表”之间的等价关系,并且可以使用char':'作为索引来dynamic构造A(:, :, :, i, :, ...)
调用任意维度。
function out = slice(A, ix, dim) subses = repmat({':'}, [1 ndims(A)]); subses{dim} = ix; out = A(subses{:});
这将完全泛化,并且将执行与原始静态A(:, :, i, :, ...)
expression式完全相同的“切片”索引操作,除了摆弄这些string来设置它们的开销之外。
或者如果你想,你可以使用sprintf
构造一个stringA(:, :, i, :, ...)
,然后调用eval()
。 但是,如果可能,我喜欢避免eval
。
请注意,您的原始实施正在使用快速操作,并应该执行得很好,大约一样快。 我只是发布这个,因为我认为它是非常可读的,不会回答你最初提出的问题,它可以被应用到其他有用的东西。
分配到切片
你也可以使用这个相同的下标单元格技术作为左值分配给数组的切片。 但是,不能直接重用切片函数,因为它返回数组的提取子集,而不是左值引用。 所以你可以做一个非常类似的function,做任务本身。
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;
在实践中,你可能还需要一个函数,它只是返回一个单元格数组中的计算索引,所以你可以携带它们并重复使用它们来进行赋值和引用。
function out = slice_subs(A, ix, dim) subses = repmat({':'}, [1 ndims(A)]); subses{dim} = ix; out = subses;
你可以尝试setdiff
和setdiff
把这个维度移到一致的位置:
function out = hslice(ndarray, d, i) subdims = setdiff(1:ndims(ndarray),d); sz = size(ndarray); outsz = sz(subdims); order = [d subdims]; ndarray = permute(ndarray,order); out = reshape(ndarray(i,:),outsz); end
例如:
d = 3; i = 2; nd = randi(23,3,3,3,2); out = hslice(nd,d,i); % out = squeeze(nd(:,:,i,:)) for d=3
但是,数据在切片之前被重写,而不是在问题中的代码。 所以,我真的去与OP的!