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

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


person Joe Kearney    schedule 02.09.2010    source источник
comment
Я также нашел следующую статью по этой теме: mathworks.com/matlabcentral/newsreader/view_thread/ 280225 У кого-нибудь есть новая информация по этой теме, будет ли она реализована?   -  person    schedule 18.05.2011
comment
Этот синтаксис действительно отлично работает в Octave. Я обнаружил эту проблему только тогда, когда у моих коллег, использующих MATLAB, были проблемы с запуском моего кода.   -  person sffc    schedule 01.02.2015
comment
MATLAB в двух словах.   -  person user76284    schedule 04.06.2018
comment
Рекурсивное извлечение также работает в Scilab (scilab.org), начиная с версии 6.   -  person Stéphane Mottelet    schedule 12.04.2019
comment
testmatrix('magi', 5)(3, 3) в Scilab и magic(5)(3, 3) в Octave работают как шарм!   -  person Foad    schedule 16.07.2019


Ответы (9)


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

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

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

person gnovice    schedule 02.09.2010
comment
Ну, что ты знаешь! хотя я согласен, что это довольно уродливо и, вероятно, менее читабельно, чем решение temp-var. +1 за впечатляющие непонятные знания Matlab! - person second; 02.09.2010
comment
Отвратительный, но очень четкий ответ. Хорошая работа! Надо было догадаться, что есть обратный путь к этому. Я думаю, что продолжу с временной переменной. - person Joe Kearney; 02.09.2010
comment
Имейте в виду, что промежуточная переменная все еще полностью создана. Так что, если цель состоит в том, чтобы сэкономить память, не создавая временную локальную переменную, не повезло. - person Sam Roberts; 21.09.2011
comment
@SamRoberts: Вы не можете обойтись без этого языка строгой оценки, такого как Matlab. Основная причина, по которой люди хотят этого, - лаконичность / удобочитаемость, а не экономия памяти. - person Mechanical snail; 17.10.2011
comment
@SamRoberts: верно, но это действительно избавляет вас от бремени вызова clear на временном (что никто никогда не делает) - временное имеет тенденцию оставаться дольше - person Rody Oldenhuis; 28.06.2013
comment
Чудесно! Я часами бродил по Интернету, чтобы найти это! Я собираюсь придерживаться питона. - person vim; 18.09.2013
comment
Горячая чертовски. Я не знал, что это возможно. В конце концов, я все же буду придерживаться временной переменной! - person rayryeng; 13.05.2014
comment
Есть ли способ использовать это с end, как в vectorReturningFunction()(1:end-1)? - person knedlsepp; 21.02.2015
comment
@knedlsepp: К сожалению, мне не удалось найти способ заставить end работать с синтаксисом subsref, который я использовал выше. - person gnovice; 26.04.2015
comment
@knedlsepp - Согласно документам end: в этом контексте end = (size(x,k)) когда используется как часть k-го индекса .. Итак, я бы сказал, что возможность использования end с subsref имеет небольшую проблему причинно-следственной связи: потому что вы пытаетесь найти size(x) до того, как станет известно x. Однако, ради свободы стрелять себе в ногу, я полагаю, что то, что вы хотите, возможно, если вы рекурсивно сделаете subsref (в пределах срока индексации, т.е. subsref(...,{1:size(subsref(...))})) и получите результат, чтобы вы могли знать его размер ... :) - person Dev-iL; 17.06.2015
comment
@ Dev-iL: Было бы здорово найти подходящее решение для этого, но я думаю, что в конце концов я все еще могу жить без него. :-) - person knedlsepp; 17.06.2015
comment
@knedlsepp - мне удалось сделать это с помощью безумно сложной команды, которая полагается на интерфейс Matlab с python и способность python к отрицательной индексации. Вот и: vectorReturningFunction = @()1:10; endminus = 4; double(py.array.array('d',py.ast.literal_eval(wrap_system(['python -c "import sys; print eval(sys.argv[1])[0:-int(sys.argv[2])]" ' regexprep(char(py.array.array('d',reshape(vectorReturningFunction(),1,[])).tolist()), ' ', '') ' ' num2str(endminus)])))). где wrap_system(): function out = wrap_system(cmd); [~,out] = system(cmd);. Если вы зададите вопрос, я объясню подробнее .. - person Dev-iL; 17.06.2015
comment
(Я знаю, что это обсуждение года назад, но ...) Что ж, если вы воспользуетесь другой возможностью, создав пользовательскую функцию (анонимную или нет), вы можете преобразовать любые (-1, 0, inf, ... ) указатель на end внутри функции ... - person BIOStheZerg; 31.10.2016
comment
Это решение можно немного улучшить, используя substruct, например: subsref(magic(5), substruct('()', {3, 3})). - person Edric; 25.06.2018
comment
Просто из любопытства - если вы введете [ subsref(A,substruct('{}',{':'})) ], он не будет вести себя так же, как _2 _... Есть какие-нибудь идеи по обходному пути? - person Rody Oldenhuis; 19.09.2018
comment
@RodyOldenhuis: Использование функциональной формы для индексации, по-видимому, также требует, чтобы вы указали количество выходных аргументов, которые вы хотите получить от функции, по умолчанию - один. Результатом операции является список, разделенный запятыми, но захватывается только первый из них. Любая попытка захватить несколько выходных аргументов не даст вам простого способа объединить их в вектор. Однако это все спорный вопрос, поскольку вы, вероятно, могли бы просто использовать _1 _: cell2mat(A) - person gnovice; 19.09.2018
comment
@SamRoberts Будет ли он автоматически clear отмечен сразу после этого? - person Minh Nghĩa; 20.04.2020
comment
@ MinhNghĩa Промежуточная переменная будет очищена одновременно с любой другой переменной, т.е. когда она выйдет за пределы области видимости. Обычно это происходит не сразу после оператора, а в конце функции (хотя все может быть иначе, если пользователь сделает что-то вроде нажатия Ctrl-C). - person Sam Roberts; 20.04.2020

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

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

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

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

вернется

ans = 16

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

Эти и другие функции теперь доступны в надстройке Функциональные программные конструкции, которая доступна через MATLAB Add-On Explorer или на Обмен файлами.

person T. Furfaro    schedule 11.02.2013
comment
Это немного более общая версия второй половины ответа gnovice; также хорошо. - person Joe Kearney; 28.02.2013
comment
А что насчет myfunc().attr? - person gerrit; 19.03.2013
comment
@gerrit, как у справки? а поле x.attr () недоступно, если у вас нет набора инструментов базы данных. - person T. Furfaro; 21.03.2013
comment
@ T.Furfaro А? Если myfunc() возвращает структуру, которая включает атрибут attr, то для доступа к attr в настоящее время мне нужно сделать S = myfunc(); S.attr. Вопрос в том, можем ли мы иметь вспомогательную функцию вроде getattr(myfunc(), 'attr') по аналогии с помощниками paren и curly. Я не понимаю, какое отношение это имеет к инструментарию базы данных. - person gerrit; 21.03.2013
comment
@gerrit Извините, полная путаница (я не знал, что ваш attr был произвольным - в db tb определена такая эксплицитность поля). Я считаю, что вы ищете getfield () - person T. Furfaro; 04.04.2013
comment
Я отредактировал ссылку на надстройку, содержащую ряд этих функций, которая доступна через проводник надстройки MATLAB или обмен файлами. - person nekomatic; 22.12.2016

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

>> 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.

person Amro    schedule 25.04.2013
comment
@RodyOldenhuis: Сейчас я не припомню, наверное, я читал это в каком-то закопанном коде;) - person Amro; 28.06.2013
comment
Оператор двоеточия (:) необходимо использовать с апострофами ':', чтобы избежать ошибки Undefined function or variable "builtin". - person Dominik; 20.11.2014
comment
@Dominik: верно, скажем, вы хотите разрезать второй столбец, это будет: builtin('_paren', magic(5), ':', 2) (в некоторых местах он работает без кавычек напрямую как :, а не ':', например, при запуске в командной строке напрямую, а не из функции . Думаю, это ошибка парсера!) - person Amro; 20.11.2014
comment
Я не думаю, что есть способ использовать end с этим? - person knedlsepp; 21.02.2015
comment
@knedlsepp: Нет, к сожалению, весь end-trickery не работает в этом синтаксисе, вам придется явно указывать в своем индексировании .. (То же ограничение применяется для большинства других перечисленных ответов) - person Amro; 21.02.2015

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

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

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

person Ian M. García    schedule 09.08.2013
comment
Это действительно хороший метод. Есть недостатки? - person mmumboss; 07.03.2014
comment
@mmumboss: это недокументированное поведение, эта функция может исчезнуть без уведомления в будущих версиях. К тому же недостатков нет. - person Daniel; 22.03.2015
comment
Начиная с MATLAB2017b, эта функциональность задокументирована. - person njspeer; 08.04.2018
comment
Как мне получить столбец или строку вывода? Например, a(1, :). Я пробовал getfield(rand(5), {1, 1:5}) и getfield(rand(5), {1:5, 1}), которые работают нормально, но не элегантно. - person ZR Han; 24.02.2021

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

tmp = magic(3);
myVar = tmp(3,3);
clear tmp
person second    schedule 02.09.2010

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

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

person titus    schedule 02.02.2012

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

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

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

value = getElem(magic(5), 3, 3);
person Vugar    schedule 01.05.2013
comment
но это именно то, что делает subref ... но в более общем смысле. - person Shai; 01.05.2013
comment
да, более общий способ, но не дружелюбный ... на мой взгляд, очень уродливый. - person Vugar; 01.05.2013

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

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

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

person Andreas GS    schedule 20.08.2012
comment
Я согласен с тем, что это более кратко, и очистка - это хорошая идея в цикле, как вы говорите, но вопрос конкретно заключался в том, можно ли избежать промежуточного присваивания. - person Joe Kearney; 21.08.2012
comment
Оператор clear значительно замедлит ваш код, лучше не использовать его, если M не слишком большой и у вас где-то не хватает памяти. - person Cris Luengo; 01.05.2021

Чтобы дополнить ответ Амро, вы можете использовать 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.
person nirvana-msu    schedule 12.05.2016
comment
На самом деле это не странно: MATLAB хранит список определенных функций, не так уж много и нужно искать. feval действует «нормально» и поэтому может в полной мере использовать этот список. builtin должен искать в другом месте, чтобы находить только встроенные функции. Вероятно, этот случай не оптимизирован так сильно, как «нормальный» случай, потому что зачем вкладывать деньги в оптимизацию того, что не используется очень часто? - person Cris Luengo; 30.06.2018