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

321

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

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

  • 2
    Я также нашел следующую статью на эту тему: mathworks.com/matlabcentral/newsreader/view_thread/280225 У кого-нибудь есть новая информация по этой теме, будет ли она реализована?
  • 2
    Этот синтаксис на самом деле отлично работает в Octave. Я обнаружил эту проблему, только когда у моих коллег, использующих MATLAB, были проблемы с запуском моего кода.
Показать ещё 1 комментарий
Теги:
indexing
matrix
return-value
variable-assignment

9 ответов

354
Лучший ответ

На самом деле можно делать то, что вы хотите, но вам нужно использовать функциональную форму оператора индексирования. Когда вы выполняете операцию индексирования с помощью (), вы фактически вызываете функцию 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

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

  • 22
    Ну, что же вы знаете! хотя я согласен, что это довольно уродливо и, вероятно, менее читабельно, чем временное решение. +1 за внушительные знания о MATLAB!
  • 52
    Это отвратительно, но очень четкий ответ. Хорошая работа! Должен был догадаться, что будет обратный путь. Я думаю, что я буду продолжать с переменной Temp.
Показать ещё 15 комментариев
108

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

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

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

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

вернет

ans = 16

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

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

  • 2
    Это немного более общий вариант второй половины ответа gnovice; также хорошо.
  • 0
    Как насчет myfunc().attr ?
Показать ещё 4 комментария
71

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

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

или для массивов ячеек:

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

Также как магия:)


UPDATE:

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

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

  • 0
    @RodyOldenhuis: Я сейчас не помню, наверное, я читал это в каком-то скрытом коде;)
  • 2
    Оператор двоеточия (:) должен использоваться с апострофами ':' чтобы избежать ошибки Undefined function or variable "builtin" .
Показать ещё 3 комментария
48

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

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

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

  • 5
    На самом деле это хороший метод. Есть ли недостатки?
  • 6
    @mmumboss: это недокументированное поведение, эта функция может исчезнуть без предварительного уведомления в будущих версиях. Помимо этого нет недостатков.
Показать ещё 1 комментарий
15

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

tmp = magic(3);
myVar = tmp(3,3);
clear tmp
  • 2
    Можно ли где-нибудь проголосовать за добавление этой функции?
  • 7
    @ EvgeniSergeev вы можете голосовать ногами, используя такой язык, как R, который поддерживает это.
12

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

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

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

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

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

value = getElem(magic(5), 3, 3);
  • 0
    но это именно то, что делает subref ... но в более общем смысле.
  • 2
    да, более общий путь, но не дружелюбный ... на мой взгляд, очень уродливый.
4

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

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

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

  • 5
    Я согласен, что это более кратко, и, как вы говорите, очистка - это хорошая идея в цикле, но вопрос был именно в том, можно ли избежать промежуточного назначения.
1

Чтобы дополнить ответ Amro, вы можете использовать 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.
  • 0
    Это на самом деле не странно: MATLAB хранит список определенных функций, поиск не так уж и сложен. feval делает «нормальную» вещь и поэтому может в полной мере использовать этот список. builtin должен искать в другом месте, поэтому он находит только встроенные функции. Вероятно, этот случай не оптимизирован почти так же хорошо, как «нормальный» случай, потому что зачем вкладывать деньги в оптимизацию чего-то, что используется не очень часто?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню