Як я можу індексувати масив MATLAB, повернутий функцією, попередньо не призначивши його локальній змінній?


363

Наприклад, якщо я хочу прочитати середнє значення з 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, виникли проблеми з моїм кодом.
sffc

2
MATLAB в двох словах.
користувач76284

1
Рекурсивний екстракція також працює в Scilab ( scilab.org ) , починаючи з версії 6
Stephane Mottelet

і testmatrix('magi', 5)(3, 3)на Scilab, і magic(5)(3, 3)на Octave обидва працюють як шарм!
Foad

Відповіді:


384

Це на самому ділі це можна робити те , що ви хочете, але ви повинні використовувати функціональну форму оператора індексування. Виконуючи операцію індексації за допомогою (), ви фактично здійснюєте виклик 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

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


26
ну що ти знаєш! хоча я згоден, це досить некрасиво і, ймовірно, менш читабельно, ніж тимчасове рішення. +1 за вражаючі незрозумілі знання з математики!
другий

57
Це огидна, але дуже чітка відповідь. Гарна робота! Якщо ви здогадувались, що в нього буде зворотний шлях. Я думаю, я продовжуватиму роботу зі змінною temp.
Джо Керні

29
Майте на увазі, що проміжна змінна все ще повністю створена. Тож якщо мета - зберегти пам'ять, не створюючи тимчасової локальної змінної, не пощастить.
Сем Робертс

8
@SamRoberts: Ви дійсно не можете обійти це на такій строгій оцінці, як Matlab. Основна причина, чому люди хочуть цього, - це стислість / читабельність, а не економія пам’яті.
Механічний равлик

5
@SamRoberts: правда, але це дійсно позбавить вас від тягаря виклику clearна тимчасове (який ніхто ніколи не робить) - тимчасовий , як правило , триматися довше
Роді Oldenhuis

131

Був просто хороший блог на Loren на мистецтві Matlab пару днів назад з парою дорогоцінних каменів , які можуть допомогти. Зокрема, за допомогою допоміжних функцій, таких як:

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

де paren()можна використовувати як

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

повернеться

ans = 16

Я також вважаю, що це буде швидше, ніж відповідь gnovice, але я не перевірив (Використовуйте профілер !!!). Однак, ви також повинні десь включити ці визначення функцій. Я особисто зробив їм самостійні функції на моєму шляху, тому що вони дуже корисні.

Ці функції та інші тепер доступні у додатку Конструкти функціонального програмування, який доступний через провідник додатків MATLAB або у файлообміні .


2
Це трохи більш загальна версія другої половини відповіді gnovice; також добре.
Джо Керні

Про що myfunc().attr?
gerrit

@gerrit, як допомагає? і поле x.attr () недоступне, якщо у вас немає панелі інструментів бази даних.
Т. Фурфаро

@ T.Furfaro Так? Якщо myfunc()повертає структуру, яка включає атрибут attr, то для доступу в attrданий момент мені потрібно зробити S = myfunc(); S.attr. Питання полягає в тому, чи можемо ми мати функцію помічника, як getattr(myfunc(), 'attr')за аналогією з помічниками parenта curlyпомічниками. Я не розумію, що це стосується панелі інструментів бази даних.
gerrit

2
@gerrit Вибачте, повна плутанина (я не знав, що ваш "attr" довільний - у db tb визначена така чіткість поля). Я вважаю, що ви шукаєте це getfield ()
Т. Фурфаро

75

Як ви ставитесь до використання недокументованих функцій:

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


@RodyOldenhuis: Я не пам’ятаю зараз, напевно, я повинен був прочитати його в якомусь закопаному коді;)
Amro

2
Оператор двокрапки (:) повинен використовуватися з апострофами, ':'щоб уникнути помилки Undefined function or variable "builtin".
Домінік

@Dominik: правильно, скажіть, ви хочете нарізати другий стовпець, це було б: builtin('_paren', magic(5), ':', 2)(у деяких місцях він працює без цитат безпосередньо, :на відміну від ':', наприклад, при запуску в командному рядку безпосередньо не зсередини функції. Я здогадуюсь це помилка в аналізаторі!)
Amro

2
Я не думаю, що існує якийсь спосіб використовувати endдля цього?
knedlsepp

2
@knedlsepp: Ні, на жаль, цілий endтрюк не працює в цьому синтаксисі, вам доведеться бути явним в індексації .. (Те саме обмеження стосується більшості інших перерахованих відповідей)
Amro

54

Принаймні, у MATLAB 2013a ви можете використовувати getfield:

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

щоб отримати елемент у (1,2)


5
Це насправді приємний метод. Якісь недоліки?
mmumboss

6
@mmumboss: Це недокументована поведінка, ця функціональність може зникнути без попереднього повідомлення в майбутніх версіях. Крім цього немає недоліків.
Даніель

6
Станом на MATLAB2017b ця функціональність задокументована.
njspeer

15

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

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

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);

1
але це саме те, що subrefробить ... але в більш загальному вигляді.
Шай

2
так, більш загальний спосіб, але не дружній ... на мою думку дуже потворний.
Вугар

4

Ваше початкове позначення - це найкоротший спосіб зробити це:

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

Якщо ви робите це в циклі, ви можете просто перепризначити M кожен раз і також проігнорувати чітке твердження.


6
Я погоджуюся, що це більш стисло, і очищення - це гарна ідея в циклі, як ви кажете, але питання було конкретно, чи можна уникнути проміжного призначення.
Джо Керні

1

Щоб доповнити відповідь Амро, ви можете використовувати 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.

Це насправді не дивно: MATLAB зберігає список визначених функцій, не так вже й багато шукати. fevalробить "нормальну" річ, і тому може повністю використовувати цей список. builtinтреба шукати в іншому місці, щоб він знаходив лише вбудовані функції. Ймовірно, цей випадок не оптимізований майже так само, як і «нормальний» випадок, бо навіщо ви вкладаєте гроші в оптимізацію чогось, що не використовується дуже часто?
Кріс Луенго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.