Как я могу индексировать массив 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.