Como ignorar elegantemente alguns valores de retorno de uma função MATLAB?

120

É possível obter o 'nésimo' valor de retorno de uma função sem precisar criar variáveis ​​fictícias para todos os n-1valores de retorno anteriores a ela?

Digamos, eu tenho a seguinte função no MATLAB:

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

Agora, suponha, eu estou interessado apenas no terceiro valor de retorno. Isso pode ser conseguido criando uma variável dummy:

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

Mas acho que isso é meio feio . Eu acho que você pode fazer algo como uma das seguintes coisas, mas não pode:

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

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Existem maneiras elegantes de fazer isso funcionar?


Até agora, a melhor solução é simplesmente usar a variableThatIWillUsevariável como dummy. Isso me impede de ter que criar uma variável fictícia real que polui o espaço de trabalho (ou que eu precisaria limpar). Resumindo: a solução é usar o variableThatIWillUsevalor de cada retorno até o interessante. Os valores de retorno depois podem simplesmente ser ignorados:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

Ainda acho que esse é um código muito feio, mas se não houver uma maneira melhor, acho que vou aceitar a resposta.

Jordi
fonte
Além de usar uma matriz de células, como descrevi na minha resposta, repetir o nome da variável provavelmente é sua única outra solução. Espero que seus nomes de variáveis ​​não sejam tão longos quanto "variableThatIWillUse". =)
gnovice
Na verdade eles são. 'manequim' era apenas um exemplo. Normalmente eu usaria 'variableThatIWillNotUse'. Outras variáveis ​​são nomeadas 'variableThatIMightUse', 'variableThatIWillUse2' e 'variableThatCanBarelyFitOnA80CharacterLine'. Estou pesquisando a correlação entre nomes longos e índices de homicídios. ;)
Jordi
26
Na verdade, desde que o R2009b, ignorando os retornos da função, é resolvido de maneira mais elegante usando o char '~'. por exemplo: [~, b] = sort (rand (10,1))
ymihere 9/10/09
1
PARA NOVOS LEITORES: ^ deve ser a resposta correta. Veja a resposta de ManWithSleeve abaixo
A.Wan
1
No seu exemplo, se você quiser apenas o terceiro argumento de saída, deverá usar: [variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func; Não há necessidade de limpar uma variável dummy. Para versões mais recentes do MATLAB> = R2009b, use [~, ~, variableThatIWillUse] = func;
Thierry Dalon 20/09/16

Respostas:

38

Isso é um hack, mas funciona:

Primeiro, uma função de exemplo rápido:

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

Agora, a chave aqui é que, se você usar uma variável duas vezes no lado esquerdo de uma atribuição de múltiplas expressões, uma atribuição anterior será derrotada pela atribuição posterior:

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

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

(editar: apenas para verificar, também verifiquei que essa técnica funciona [mu,mu,mu]=polyfit(x,y,n)se tudo o que você mais gosta polyfité o terceiro argumento)


editar: existe uma abordagem melhor; veja a resposta de ManWithSleeve .

Jason S
fonte
7
Não tinha pensado em resolvê-lo assim. No entanto, sinto que essa solução sacrifica a clareza da intenção pela inteligência.
Jukka Dahlbom
5
Pessoalmente, apenas uso [junk, junk, c] = function_call () e assumo que "junk" nunca é uma variável importante e, se contiver muita memória, eu a limpo, se necessário.
Jason S
5
para o downvoter: Por que o -1? Esta resposta foi escrita antes do lançamento do R2009b, portanto a resposta do @ ManWithSleeve não teria funcionado no momento. Agora, é claro, essa é a abordagem correta.
Jason S
2
Talvez um comentário na primeira linha da sua resposta seja útil? Eu só vim aqui pelo google, então parece que vale a pena atualizar.
FVD 23/04
A tarefa da esquerda para a direita não é oficialmente garantida pelo The MathWorks; portanto, você provavelmente não deve confiar em usar c após [c, c, c] = myFunc (). (Veja o comentário # 26 aqui: blogs.mathworks.com/loren/2009/09/11/… )
Matt Krause
226

Com o MATLAB Versão 7.9 (R2009b), você pode usar um ~, por exemplo,

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

Observe que ,não é opcional. Apenas digitar [~ ~ var]não funcionará e gerará um erro.

Veja as notas de versão para detalhes.

ManWithSleeve
fonte
3
Meio irritante que não seja "_". (Suponho que já foi tirada?)
Samb
4
@SamB: embora usando o notoperador em don't careque não é ruim
Tobias KIENZLER
28
Observe que ,não é opcional. Digitando apenas [~ ~ var]irá não trabalho, e lançará um erro.
eykanal
Eu diria que esta é a resposta "correta". O outro são apenas hacks para corrigir um problema que não existe. Sem trocadilhos embora ...
Patrik
6
A questão foi colocada em 2009 antes do R2009b, quando o ~ não funcionou.
Tom Anderson
37

Se você deseja usar um estilo em que uma variável será deixada cair no bucket de bits, uma alternativa razoável é

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

ans é, obviamente, a variável de lixo padrão do matlab, sendo substituída com frequência no decorrer de uma sessão.

Embora eu goste do novo truque que o MATLAB agora permite, usar um ~ para designar uma variável de retorno ignorada, isso é um problema de compatibilidade com versões anteriores, pois os usuários de versões mais antigas não poderão usar seu código. Eu geralmente evito usar coisas novas assim até que pelo menos alguns lançamentos do MATLAB tenham sido lançados para garantir que haverá muito poucos usuários no caminho. Por exemplo, mesmo agora, acho que as pessoas ainda estão usando uma versão do MATLAB com idade suficiente para não poderem usar funções anônimas.


fonte
7
Sim, é inteligente, mas o editor nativo do Matlab emitirá um aviso se você atribuir algo à variável ans. Eu não acho que têm avisos são muito elegante ...
Jordi
11
Você pode desativar o aviso. Termine a linha com esta sequência de comentários% # ok O Mlint ignorará isso. Sem avisos.
13

Aqui está outra opção que você pode usar. Primeiro, crie uma matriz de células para capturar todas as saídas (você pode usar a função NARGOUT para determinar quantas saídas uma determinada função retorna):

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

Em seguida, chame a função da seguinte maneira:

[a{:}] = func();

Em seguida, basta remover o elemento de um que você deseja e substituir um :

a = a{3};  % Get the third output
gnovice
fonte
9

Eu escrevi uma k-ésima função:


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

então você pode ligar

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

você também pode encerrar a função como

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

após o qual você usa

val_i_want = func_i_want(func_input_1,func_input_2);

observe que há uma sobrecarga associada ao uso de funções anônimas como essa, e isso não é algo que eu faria no código que seria chamado milhares de vezes.

shabbychef
fonte
4

No Matlab 2010a, encontrei uma maneira elegante de fazer o que você está pedindo. É simplesmente usar o caractere "~" (sem as aspas, é claro) como sua variável dummy (quantas você desejar ao retornar vários parâmetros). Isso também funciona para parâmetros de entrada para funções, se as funções forem projetadas para manipular dados ausentes. Não sei se isso existia nas versões anteriores, mas me deparei com isso recentemente.

Sam
fonte
11
Você não viu a resposta anterior?
Yuk
1

Você pode criar uma função (ou função anônima) que retorne apenas as saídas selecionadas, por exemplo

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

Então você pode chamar sua função assim:

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

Ou você pode atribuir a saída a uma variável:

output(1,2:4) = select(func,1:3);
Dave
fonte
não funciona para mim. Tenteidecimatedfftx = select(fft(x,12),1:4:12);
NotGaeL
1
select(func,2)chamadas func(2). Não vejo onde isso seleciona argumentos de saída.
Cris Luengo 12/12
0

Existe alguma razão para não usar ans (n), assim:

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

size(a);

b=ans(2);

Dá b = 10 e dessa forma não seria compatível com todas as versões do Matlab?

Além disso, isso funciona para obter o segundo argumento de saída quando você não sabe quantos argumentos haverá! Considerando que, se você fizer isso:

[~, b] = size(a);

Então b = 8000! (Você precisa terminar com ~, para pegar mais argumentos!)

user1596274
fonte
Essa resposta assume que a variável que está sendo retornada é um vetor, que provavelmente não foi o que o OP significava.
Neil Traft 26/03/2015
Isso não faz sentido. size(a)e [b,c]=size(a)devolver coisas diferentes. As funções no MATLAB alteram o comportamento com base no número de argumentos de saída.
Cris Luengo
Estou tendo dificuldade para entender esta resposta. Não sei como isso contribui para a qualidade das respostas aqui, muito menos que isso não responda diretamente à pergunta original.
rayryeng
Seis anos depois, eu não uso mais o Matlab. Tanto quanto me lembro, a função "size ()" era irrelevante - apenas a usei como uma função que retornaria vários argumentos. O ponto é que eu posso simplesmente chamar func () e depois ans (n) para obter o valor da variável retornada número n. Isso pareceu funcionar bem em determinadas situações e ser compatível com versões anteriores. Pode funcionar apenas com certas funções, é claro, ou tipos de variáveis, qualquer que seja. É o máximo que posso ajudar seis anos depois.
user1596274