По формо-независимой нарезке ndarrays
В этом посте я использую термин ломтик для обозначения подмассива B_i
n- мерного массива A
такой, что size(B_i, d)
равен 1, для некоторого измерения d
, A
состоит из size(A, d)
такие кусочки, соединенные вдоль измерения d
,
Например, если ndims(A)
6 и d
3, то выражения вида
A(:, :, i, :, :, :)
за i
в 1:size(A, d)
представлять все срезы (вдоль измерения d
) которые составляют A
,
Проблема с выражением типа A(:, :, i, :, :, :)
состоит в том, что он не может быть символически обобщен на срезы вдоль измерения, отличного от 3, в массивах, имеющих число измерений, отличное от 6. Например, чтобы получить 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
Есть ли встроенный или, по крайней мере, более эффективный способ достижения того же результата (без учета формы)?
2 ответа
Да уж. Вы можете использовать эквивалентность между разыменованными массивами ячеек и "списками, разделенными запятыми", и тот факт, что вы можете использовать символ ":" в качестве индекса для динамического построения этого A(:, :, :, i, :, ...)
вызов для произвольных измерений.
function out = slice(A, ix, dim)
subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
out = A(subses{:});
Это будет обобщать полностью и будет выполнять ту же самую операцию индексации "среза", что и исходная статическая A(:, :, i, :, ...)
выражение, помимо накладных расходов на эти строки, чтобы настроить его.
Или, если вы хотите, вы можете просто использовать sprintf
построить это A(:, :, i, :, ...)
в виде строки, а затем вызвать eval()
в теме. Но мне нравится избегать eval
если вообще возможно.
Обратите внимание, что ваша первоначальная реализация использует быстрые операции и должна работать очень хорошо, примерно так же быстро, как эта. Я просто публикую это, потому что я думаю, что он очень удобочитаемый, отвечает на ваш вопрос в том виде, в котором он был задан изначально, и его можно применить к другим полезным материалам.
Назначение ломтикам
Вы также можете использовать эту же технику "индексы в ячейке" в качестве lvalue для присвоения фрагментам массива. Вы не можете использовать функцию слайса напрямую, так как она возвращает извлеченное подмножество массива, а не ссылку на lvalue. Таким образом, вы можете сделать очень похожую функцию, которая выполняет само назначение.
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;
Ты можешь попробовать permute
а также 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
НО, данные переписываются до нарезки здесь, а не с кодом в вопросе. Итак, я бы на самом деле пошел с ОП!