Как я могу индексировать массив MATLAB, возвращаемый функцией, без предварительного присвоения его локальной переменной?

Например, если я хочу прочитать среднее значение из magic(5)Я могу сделать это так:

M = magic(5);
value = M(3,3);

получить value == 13, Я хотел бы иметь возможность сделать что-то вроде этого:

value = magic(5)(3,3);
value = (magic(5))(3,3);

обойтись без промежуточной переменной. Тем не менее, MATLAB жалуется на Unbalanced or unexpected parenthesis or bracket в первых скобках перед 3,

Можно ли прочитать значения из массива / матрицы без предварительного присвоения ее переменной?

9 ответов

Решение

На самом деле можно делать то, что вы хотите, но вы должны использовать функциональную форму оператора индексации. Когда вы выполняете операцию индексирования с помощью () вы на самом деле звоните subsref функция. Итак, даже если вы не можете сделать это:

value = magic(5)(3, 3);

Вы можете сделать это:

value = subsref(magic(5), struct('type', '()', 'subs', {{3, 3}}));

Уродливо, но возможно.;)

В общем, вам просто нужно изменить шаг индексации на вызов функции, чтобы у вас не было двух наборов скобок, следующих сразу за друг другом. Другой способ сделать это - определить собственную анонимную функцию для индексирования по подписке. Например:

subindex = @(A, r, c) A(r, c);     % An anonymous function for 2-D indexing
value = subindex(magic(5), 3, 3);  % Use the function to index the matrix

Однако, когда все сказано и сделано, решение для временных локальных переменных становится гораздо более читабельным, и, безусловно, то, что я бы предложил.

Пару дней назад была просто хорошая запись в блоге о Лорен о искусстве Matlab с парой драгоценных камней, которые могли бы помочь. В частности, используя вспомогательные функции, такие как:

paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};

где paren() можно использовать как

paren(magic(5), 3, 3);

вернется

ans = 16

Я также предположил бы, что это будет быстрее, чем ответ gnovice, но я не проверял (Используйте профилировщик!!!). Тем не менее, вы также должны включить эти определения функций где-то. Я лично сделал их независимыми функциями на моем пути, потому что они очень полезны.

Эти и другие функции теперь доступны в дополнении " Functional Programming Constructs", которое доступно через обозреватель дополнений MATLAB или в " Файловом обмене".

Как вы относитесь к использованию недокументированных функций:

>> builtin('_paren', magic(5), 3, 3)               %# M(3,3)
ans =
    13

или для клеточных массивов:

>> builtin('_brace', num2cell(magic(5)), 3, 3)     %# C{3,3}
ans =
    13

Прямо как волшебство:)


ОБНОВИТЬ:

Плохая новость, вышеупомянутый хак больше не работает в R2015b! Это нормально, это была недокументированная функциональность, и мы не можем полагаться на нее как на поддерживаемую функцию:)

Для тех, кто интересуется, где найти этот тип вещей, посмотрите в папке fullfile(matlabroot,'bin','registry'), Там есть куча XML-файлов, в которых перечислены все виды вкусностей. Имейте в виду, что прямой вызов некоторых из этих функций может легко привести к сбою сеанса MATLAB.

По крайней мере, в MATLAB 2013a вы можете использовать getfield лайк:

a=rand(5);
getfield(a,{1,2}) % etc

чтобы получить элемент в (1,2)

К сожалению синтаксис вроде magic(5)(3,3) не поддерживается Matlab. вам нужно использовать временные промежуточные переменные. Вы можете освободить память после использования, например

tmp = magic(3);
myVar = tmp(3,3);
clear tmp

Обратите внимание, что если вы сравните время выполнения со стандартным способом (присвойте результат и затем получите доступ к записям), они будут точно такими же.

subs=@(M,i,j) M(i,j);
>> for nit=1:10;tic;subs(magic(100),1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0103

>> for nit=1:10,tic;M=magic(100); M(1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0101

На мой взгляд, суть в том, что в MATLAB нет указателей, с этим нужно жить.

Это может быть проще, если вы сделаете новую функцию:

function [ element ] = getElem( matrix, index1, index2 )
    element = matrix(index1, index2);
end

и затем используйте это:

value = getElem(magic(5), 3, 3);

Ваша начальная запись является наиболее кратким способом сделать это:

M = magic(5);  %create
value = M(3,3);  % extract useful data
clear M;  %free memory

Если вы делаете это в цикле, вы можете просто каждый раз переназначать M и игнорировать оператор clear.

Чтобы дополнить ответ Амро, вы можете использовать feval вместо builtin, На самом деле нет никакой разницы, если только вы не попытаетесь перегрузить функцию оператора:

BUILTIN (...) аналогичен FEVAL(...), за исключением того, что он будет вызывать оригинальную встроенную версию функции, даже если существует перегруженная версия (чтобы это работало, вы никогда не должны перегружать BUILTIN).

>> feval('_paren', magic(5), 3, 3)               % M(3,3)
ans =
    13

>> feval('_brace', num2cell(magic(5)), 3, 3)     % C{3,3}
ans =
    13

Интересно то, что feval кажется, чуть-чуть быстрее, чем builtin (на ~3,5%), по крайней мере, в Matlab 2013b, что странно, учитывая, что feval нужно проверить, не перегружена ли функция, в отличие builtin:

>> tic; for i=1:1e6, feval('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 49.904117 seconds.
>> tic; for i=1:1e6, builtin('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 51.485339 seconds.
Другие вопросы по тегам