Как элегантно игнорировать некоторые возвращаемые значения функции MATLAB?

120

Возможно ли получить возвращаемое значение n-го значения из функции без необходимости создавать 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;

Я все еще считаю, что это очень уродливый код, но если нет лучшего способа, я думаю, что приму ответ.

Jordi
источник
Помимо использования массива ячеек, как я описал в своем ответе, повторение имени переменной, вероятно, является вашим единственным другим решением. Надеюсь, ваши имена переменных не такие длинные, как «variableThatIWillUse». =)
gnovice
На самом деле они есть. «манекен» был просто примером. Обычно я бы использовал variableThatIWillNotUse. Другие переменные называются variableThatIMightUse, variableThatIWillUse2 и variableThatCanBarelyFitOnA80CharacterLine. Я исследую корреляцию между длинными именами и рейтингами убийств. ;)
Jordi
26
На самом деле, поскольку в R2009b игнорирование возвратов функций решается более элегантно с использованием символа '~' -Char. например: [~, b] = sort (rand (10,1))
ymihere
1
ДЛЯ НОВЫХ ЧИТАТЕЛЕЙ: ^ должен быть правильным ответом. См . Ответ ManWithSleeve ниже
Ван
1
В вашем примере, если вам нужен только третий выходной аргумент, вы должны использовать: [variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func; Не нужно очищать фиктивную переменную. Для более новых версий MATLAB> = R2009b используйте [~, ~, variableThatIWillUse] = 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- это третий аргумент)


изменить: есть лучший подход; вместо этого см . ответ ManWithSleeve .

Джейсон С
источник
7
Не думал о решении вот так. Однако я чувствую, что это решение приносит в жертву ясность намерения в пользу сообразительности.
Юкка Дальбом,
5
Лично я просто использую [junk, junk, c] = function_call () и предполагаю, что «мусор» никогда не является важной переменной, и если он содержит много памяти, я при необходимости очищу ее.
Джейсон С.
5
голосующему против: Почему -1? Этот ответ был написан до того, как был выпущен R2009b, поэтому ответ @ ManWithSleeve не сработал бы в то время. Конечно, это правильный подход.
Jason S
2
Может быть, вам будет полезен комментарий в первой строке вашего ответа? Я только что зашел сюда через гугл, так что вроде стоит обновить.
FvD
Присваивание слева направо официально не гарантируется MathWorks, поэтому вам, вероятно, не следует полагаться на использование c после [c, c, c] = myFunc (). (См. Комментарий № 26 здесь: blogs.mathworks.com/loren/2009/09/11/… )
Мэтт Краузе,
226

С MATLAB версии 7.9 (R2009b) вы можете использовать ~, например,

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

Обратите внимание, что ,это не обязательно. Просто печатать [~ ~ var]не получится и выдаст ошибку.

См. Подробности в примечаниях к выпуску .

ManWithSleeve
источник
3
Раздражает, что это не "_". (Полагаю, это уже было снято?)
SamB
4
@SamB: хотя использование notоператора as in don't careтоже не так уж плохо
Тобиас Кинцлер
28
Обратите внимание, что ,это не обязательно. Просто набрав [~ ~ var]будет не работать, и выдаст ошибку.
eykanal
Я бы сказал, что это «правильный» ответ. Другие - это просто хаки для решения проблемы, которой не существует. Но это не каламбур ...
Патрик
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
gnovice
источник
9

Я написал функцию kth out:


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

обратите внимание, что существуют накладные расходы, связанные с использованием подобных анонимных функций, и это не то, что я бы делал в коде, который будет вызываться тысячи раз.

shabbychef
источник
4

В Matlab 2010a я нашел изящный способ делать то, о чем вы просите. Просто использовать символ «~» (конечно, без кавычек) в качестве фиктивной переменной (сколько угодно при возврате нескольких параметров). Это также работает для входных параметров функций, если функции предназначены для обработки отсутствующих данных. Я не знаю, существовало ли это в предыдущих версиях, но я недавно столкнулся с этим.

Сэм
источник
11
Разве вы не видели предыдущий ответ?
yuk
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! (Вам нужно заканчивать на ~, чтобы поймать больше аргументов!)

user1596274
источник
Этот ответ предполагает, что возвращаемая переменная является вектором, что, вероятно, не то, что имел в виду OP.
Нил Трафт,
Это не имеет никакого смысла. size(a)и [b,c]=size(a)вернуть разные вещи. Функции в MATLAB изменяют поведение на основе количества выходных аргументов.
Крис Луенго
Мне сложно понять этот ответ. Я не знаю, как это влияет на качество ответов здесь, не говоря уже о том, что это не дает прямого ответа на исходный вопрос.
rayryeng
Прошло 6 лет, и я больше не использую Matlab. Насколько я помню, функция size () не имела значения - я просто использовал ее как функцию, которая возвращала бы несколько аргументов. Дело в том, что я могу просто вызвать func (), а затем ans (n), чтобы получить значение возвращаемой переменной номер n. Это, похоже, хорошо работало в определенных ситуациях и было обратно совместимо. Конечно, он может работать только с определенными функциями или типами переменных, что угодно. Это все, что я могу помочь через 6 лет.
user1596274