Индексирование неизвестной размерной матрицы

У меня есть нефиксированная размерная матрица M, из которой я хочу получить доступ к одному элементу. Индексы элементов содержатся в векторе J.

Итак, например:

M = rand(6,4,8,2);
J = [5 2 7 1];

output = M(5,2,7,1)

На этот раз M имеет 4 измерения, но это не известно заранее. Это зависит от настройки алгоритма, который я пишу. Также может быть, что

M = rand(6,4);
J = [3 1];

output = M(3,1)

поэтому я не могу просто использовать

output=M(J(1),J(2))

Я думал об использовании sub2ind, но для этого также нужны переменные, разделенные запятыми.

@gnovice

это работает, но я намерен довольно часто использовать этот вид извлечения элементов из матрицы M. Так что, если мне нужно создать временную переменную cellJ каждый раз, когда я получаю доступ к M, не будет ли это значительно замедлить вычисление?

Я мог бы написать отдельную функцию

function x= getM(M,J)
    x=M(J(1),J(2));
    % M doesn't change in this function, so no mem copy needed = passed by reference
end

и адаптировать его для различных конфигураций алгоритма. Это, конечно, скорость против гибкости, которую я не включил в мой вопрос.

НО: это доступно только для получения элемента, для установки нет другого способа, кроме фактического использования индексов (и предпочтительно линейного индекса). Я все еще думаю, что sub2ind - это вариант. Конечный результат, который я имел в виду, был примерно таким:

function idx = getLinearIdx(J, size_M)
    idx = ...
end

Результаты:

function lin_idx = Lidx_ml( J, M )%#eml
%LIDX_ML converts an array of indices J for a multidimensional array M to
%linear indices, directly useable on M
%
% INPUT
%   J       NxP matrix containing P sets of N indices
%   M       A example matrix, with same size as on which the indices in J
%           will be applicable.
%
% OUTPUT
%   lin_idx Px1 array of linear indices
%

% method 1
%lin_idx = zeros(size(J,2),1);
%for ii = 1:size(J,2)
%    cellJ = num2cell(J(:,ii)); 
%    lin_idx(ii) = sub2ind(size(M),cellJ{:}); 
%end

% method 2
sizeM = size(M);
J(2:end,:) = J(2:end,:)-1;
lin_idx = cumprod([1 sizeM(1:end-1)])*J;

end

метод 2 равен 20 (небольшое количество индексов (=P) для преобразования) в 80 (большое количество индексов (=P)) раз быстрее, чем метод 1. простой выбор

Ответ 1

Для общего случая, когда J может быть любой длины (которая, как я полагаю, всегда соответствует количеству измерений в M), у вас есть несколько вариантов:

  1. Вы можете поместить каждую запись J в ячейку массива ячеек, используя функцию num2cell, а затем создать список разделенных запятыми из этого массива ячеек, используя оператор двоеточия:

    cellJ = num2cell(J);
    output = M(cellJ{:});
    
  2. Вы можете обойти функцию sub2ind и самостоятельно вычислить линейный индекс с небольшим количеством математики:

    sizeM = size(M);
    index = cumprod([1 sizeM(1:end-1)]) * (J(:) - [0; ones(numel(J)-1, 1)]);
    output = M(index);
    

Ответ 2

Вот версия опции gnovices 2), которая позволяет обрабатывать всю матрицу индексов, где каждая строка содержит один индекс. Например, для 3 индексов:

J = [5 2 7 1 
     1 5 2 7
     4 3 9 2];

sizeM = size(M);
idx = cumprod([1 sizeX(1:end-1)])*(J - [zeros(size(J,1),1) ones(size(J,1),size(J,2)-1)]).';