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

Например, если я хочу прочитать среднее значение из 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 ]

369 голосов
/ 02 сентября 2010

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

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

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

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

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

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

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

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

127 голосов
/ 11 февраля 2013

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

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

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

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

вернется

ans = 16

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

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

75 голосов
/ 25 апреля 2013

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

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

или для массивов:

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

Так же, как магия :) 1007 *


UPDATE:

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

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

52 голосов
/ 09 августа 2013

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

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

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

15 голосов
/ 02 сентября 2010
К сожалению, синтаксис

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

tmp = magic(3);
myVar = tmp(3,3);
clear tmp
12 голосов
/ 02 февраля 2012

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

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 нет указателей, с этим нужно жить.

6 голосов
/ 01 мая 2013

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

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

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

value = getElem(magic(5), 3, 3);
4 голосов
/ 20 августа 2012

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

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

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

1 голос
/ 12 мая 2016

Чтобы дополнить ответ Амро, вы можете использовать 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.
...