Як елегантно ігнорувати деякі повернені значення функції MATLAB?


120

Чи можна отримати функцію повернення 'nth' від функції, не створюючи n-1перед цим фіктивних змінних для всіх повернених значень?

Скажімо, у MATLAB у мене є така функція:

function [a,b,c,d] = func()
a = 1;
b = 2;
c = 3;
d = 4;

Тепер припустимо, мене цікавить лише третя повернена вартість. Це можна досягти, створивши одну фіктивну змінну:

[dummy, dummy, variableThatIWillUse, dummy] = func;
clear dummy;

Але я думаю, що це щось некрасиво . Я думаю, що ви можете зробити щось на зразок однієї з наступних речей, але ви не можете:

[_, _, variableThatIWillUse, _] = func;

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Чи є якісь елегантні способи зробити це, які б спрацювали?


Поки найкращим рішенням є просто використання параметра " variableThatIWillUseфіктивна". Це рятує мене від необхідності створювати справжню змінну манекена, що забруднює робочий простір (або що мені потрібно буде очистити). Коротше кажучи: рішення полягає в тому, щоб використовувати значення variableThatIWillUseдля кожного повернення вгору до тих пір, поки це цікаве. Повернення значень після може бути просто проігноровано:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

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


Крім використання масиву комірок, як я описав у своїй відповіді, повторення імені змінної, ймовірно, є вашим єдиним іншим рішенням. Сподіваємось, ваші імена змінних не є такими ж, як "variaThatIWillUse". =)
gnovice

Насправді вони є. "манекен" був лише прикладом. Зазвичай я використовую 'variaThatIWillNotUse'. Інші змінні називаються 'зміннимиThatIMightUse', 'зміннимиThatIWillUse2' та 'зміннимиThatCanBarelyFitOnA80CharacterLine'. Я досліджую співвідношення між довгими іменами та рейтингами вбивств. ;)
Джорді

26
Насправді, оскільки функція ігнорування R2009b повертає функцію, вирішується більш елегантно за допомогою '~' -Char. напр .: [~, b] = сортувати (rand (10,1))
ymihere

1
ДЛЯ НОВИХ ЧИТАТІВ: ^ повинна бути правильною відповіддю. Дивіться відповідь ManWithSleeve нижче
A.Wan

1
У вашому прикладі, якщо ви хочете лише третій вихідний аргумент, ви будете використовувати: [зміннийThatIWillUse, зміннийThatIWillUse, зміннийThatIWillUse] = func; Не потрібно очищати фіктивну змінну. Для новіших версій MATLAB> = R2009b використовуйте [~, ~, зміннийThatIWillUse] = func;
Тіррі Далон

Відповіді:


38

Це дещо хак, але це працює:

Спочатку швидкий приклад функції:

Func3 = @() deal(1,2,3);
[a,b,c]=Func3();
% yields a=1, b=2, c=3

Тепер ключовим тут є те, що якщо ви використовуєте змінну двічі в лівій частині присвоєння з декількома виразами, попереднє призначення клобується на наступне призначення:

[b,b,c]=Func3();
% yields b=2, c=3

[c,c,c]=Func3();
% yields c=3

(редагувати: просто щоб перевірити, я також перевірив, чи працює ця методика, [mu,mu,mu]=polyfit(x,y,n)якщо все, що вам цікаво, polyfit- це 3-й аргумент)


редагувати: є кращий підхід; див замість відповіді ManWithSleeve .


7
Не думав про таке вирішення. Однак я відчуваю, що це рішення жертвує ясністю наміру розумності.
Jukka Dahlbom

5
Я особисто просто використовую [junk, junk, c] = function_call () і припускаю, що "мотлох" ніколи не є важливою змінною, і якщо він містить багато пам'яті, я очищую його, якщо потрібно.
Джейсон S

5
до низового: Чому -1? Ця відповідь була написана ще до звільнення R2009b, тому відповідь @ ManWithSleeve тоді не працювала б. Зараз, звичайно, це правильний підхід.
Jason S

2
Можливо, коментар у першому рядку вашої відповіді буде корисним? Я щойно прийшов сюди через google, тож, здається, варто оновити.
FvD

The MathWorks офіційно не присвоює призначення ліворуч праворуч, тому ви, ймовірно, не повинні покладатися на використання c після [c, c, c] = myFunc (). (Дивіться коментар №26 тут: blogs.mathworks.com/loren/2009/09/11/… )
Метт Крауз

226

З MATLAB версії 7.9 (R2009b) ви можете використовувати ~, наприклад,

[~, ~, variableThatIWillUse] = myFunction();

Зауважте, що ,це необов'язково. Просто набрати текст [~ ~ var]не вийде, і призведе до помилки.

Докладніше див. Примітки до випуску .


3
Вигляд дратує, що це не "_". (Я вважаю, що це вже було прийнято?)
SamB

4
@SamB: хоча використання notоператора як don't careі не так вже й погано
Tobias Kienzler

28
Зверніть увагу, що ,це необов'язково. Просто набрати текст не[~ ~ var] вийде , і призведе до помилки.
ейканал

Я б сказав, що це "правильна" відповідь. Інші - це просто хаки, щоб виправити проблему, яка не існує. Жоден каламбур не призначений, хоча ...
патрік

6
Питання було поставлене в 2009 році до R2009b, в той час ~ не працювало.
Том Андерсон

37

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

[ans,ans,variableThatIWillUse] = myfun(inputs);

ans, звичайно, за замовчуванням змінна непотрібна для matlab, перезаписується часто під час сеансу.

Хоча мені подобається новий фокус, який зараз дозволяє MATLAB, використовуючи ~ для позначення ігнорованої змінної повернення, це проблема для зворотної сумісності, оскільки користувачі старих версій не зможуть використовувати ваш код. Я, як правило, уникаю таких нових речей, поки не буде видано щонайменше декілька релізів MATLAB, щоб переконатися, що в спокої залишиться дуже мало користувачів. Наприклад, навіть зараз я знаходжу, що люди все ще використовують досить старий реліз MATLAB, що вони не можуть використовувати анонімні функції.


7
Так, це розумно, але рідний редактор Matlab видасть попередження, якщо ви присвоїте що-небудь змінної ans. Я не думаю, що попередження дуже елегантні ...
Джорді

11
Ви можете вимкнути попередження. Закінчіть рядок з цим рядком коментарів% # ok Mlint буде ігнорувати це. Ніяких попереджень

13

Ось ще один варіант, який ви можете використовувати. Спочатку зробіть масив комірок, щоб захопити всі результати (ви можете використовувати функцію NARGOUT для визначення кількості виходів даної функції):

a = cell(1,3);  % For capturing 3 outputs
% OR...
a = cell(1,nargout(@func));  % For capturing all outputs from "func"

Потім викличте функцію так:

[a{:}] = func();

Потім просто видалити елемент з , що ви хочете, і перезаписати :

a = a{3};  % Get the third output

9

Я написав kth-функцію:


function kth = kthout(k,ffnc,varargin)
%% kthout: take the kth varargout from a func call %FOLDUP
% 
% kth = kthout(k,ffnc,varargin)
%
% input:
%  k                      which varargout to get
%  ffnc                   function to call;
%  varargin               passed to ffnc;
% output:
%  kth                    the kth argout;
% global:
% nb: 
% See also:
% todo:
% changelog: 
%
%% %UNFOLD

[outargs{1:k}]  = feval(ffnc,varargin{:});
kth                         = outargs{k};

end %function

Ви можете зателефонувати

val_i_want  = kthout(3,@myfunc,func_input_1,func_input_2); %etc

Ви також можете завершити функцію, як

func_i_want = @(varargin)(kthout(3,@myfunc,varargin{:}));  %assuming you want the 3rd output.

після чого ви використовуєте

val_i_want = func_i_want(func_input_1,func_input_2);

зауважте, що з використанням анонімних функцій, подібних до цього, існує накладні витрати, і це не те, що я б робив у коді, який би називався тисячі разів.


4

У Matlab 2010a я знайшов акуратний спосіб робити те, що ви просите. Просто використовувати символ "~" (без лапок, звичайно) як змінну фіктивного типу (стільки, скільки вам потрібно, коли повертаєте кілька параметрів). Це також працює для введення параметрів для функцій, якщо функції призначені для обробки відсутніх даних. Я не знаю, чи існувало це в попередніх версіях, але я нещодавно натрапив на нього.


11
Ви не бачили попередньої відповіді?
юк

1

Ви можете зробити функцію (або анонімну функцію), яка повертає лише вибрані результати, наприклад

select = @(a,b) a(b);

Тоді ви можете назвати свою функцію так:

select(func,2);
select(func,1:3);

Або ви можете призначити вихідну змінну:

output(1,2:4) = select(func,1:3);

не працює для мене. Пробувавdecimatedfftx = select(fft(x,12),1:4:12);
NotGaeL

1
select(func,2)дзвінки func(2). Я не бачу, де це вибирає вихідні аргументи.
Кріс Луенго

0

Чи є якісь причини не використовувати ans (n), як це:

a=rand([5 10 20 40]);

size(a);

b=ans(2);

Дає b = 10, і чи цей спосіб не буде сумісний з усіма версіями Matlab?

Крім того, це працює для отримання другого вихідного аргументу, коли ви не знаєте, скільки буде аргументів! Беручи до уваги, якщо ви це зробите:

[~, b] = size(a);

Тоді b = 8000! (Вам потрібно закінчити з ~, щоб отримати більше аргументів!)


Ця відповідь передбачає, що змінна повертається вектором, який, мабуть, не був тим, що означав ОП.
Ніл Трафт

Це не має сенсу. size(a)і [b,c]=size(a)повертати різні речі. Функції в MATLAB змінюють поведінку на основі кількості вихідних аргументів.
Кріс Луенго

Мені важко зрозуміти цю відповідь. Я не знаю, як це сприяє якості відповідей тут, не кажучи вже про те, що це не відповідає безпосередньо на початкове запитання.
rayryeng

Це через 6 років, і я більше не використовую Matlab. Наскільки я пам’ятаю, функція «size ()» була неактуальною - я просто використовував її як функцію, яка повертала б кілька аргументів. Справа в тому, що я можу просто викликати func (), а потім ans (n), щоб отримати значення повернутої змінної числа n. Це, здається, добре працює в певних ситуаціях і бути сумісним назад. Він може працювати лише з певними функціями, звичайно, або змінними типами, незалежно від того. Це стільки, скільки я можу допомогти через 6 років.
користувач1596274
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.