web-dev-qa-db-fra.com

Comment ignorer avec élégance certaines valeurs de retour d'une fonction MATLAB?

Est-il possible d'obtenir la "nième" valeur de retour d'une fonction sans avoir à créer de variables fictives pour toutes les valeurs de retour n-1 Avant elle?

Disons que j'ai la fonction suivante dans MATLAB:

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

Supposons maintenant que je ne suis intéressé que par la valeur de retour troisième. Cela peut être accompli en créant une variable fictive:

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

Mais je pense que c'est un peu moche. Je pense que vous pourriez peut-être faire quelque chose comme l'une des choses suivantes, mais vous ne pouvez pas:

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

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Existe-t-il des moyens élégants de faire cela qui fonctionnent?


Jusqu'à présent, la meilleure solution consiste à simplement utiliser le variableThatIWillUse comme variable fictive. Cela m'évite d'avoir à créer une variable factice réelle qui pollue l'espace de travail (ou que je devrais effacer). En bref: la solution est d'utiliser le variableThatIWillUse pour chaque valeur de retour jusqu'à celle intéressante. Les valeurs de retour après peuvent simplement être ignorées:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

Je pense toujours que c'est un code très moche, mais s'il n'y a pas de meilleure façon, alors je suppose que j'accepterai la réponse.

115
Jordi

C'est un peu un hack mais ça marche:

D'abord un exemple de fonction rapide:

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

Maintenant, la clé ici est que si vous utilisez une variable deux fois dans le côté gauche d'une affectation à expressions multiples, une affectation antérieure est assaillie par la dernière affectation:

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

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

(edit: juste pour vérifier, j'ai également vérifié que cette technique fonctionne avec [mu,mu,mu]=polyfit(x,y,n) si tout ce qui vous intéresse dans polyfit est le 3ème argument)


edit: il y a une meilleure approche; voir la réponse de ManWithSleeve à la place.

38
Jason S

Avec MATLAB version 7.9 (R2009b), vous pouvez utiliser un ~, par exemple,

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

Notez que le , n'est pas facultatif. Il suffit de taper [~ ~ var] ne fonctionnera pas et générera une erreur.

Voir notes de version pour plus de détails.

224
ManWithSleeve

Si vous souhaitez utiliser un style où une variable sera laissée tomber dans le compartiment de bits, alors une alternative raisonnable est

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

ans est bien sûr la variable indésirable par défaut pour matlab, souvent écrasée au cours d'une session.

Bien que j'aime la nouvelle astuce que MATLAB autorise maintenant, en utilisant un ~ pour désigner une variable de retour ignorée, c'est un problème de compatibilité descendante, dans la mesure où les utilisateurs des versions plus anciennes ne pourront pas utiliser votre code. J'évite généralement d'utiliser de nouvelles choses comme ça jusqu'à ce qu'au moins quelques versions de MATLAB aient été publiées pour garantir qu'il ne restera que très peu d'utilisateurs. Par exemple, même maintenant, je trouve que les gens utilisent toujours une version MATLAB suffisamment ancienne pour qu'ils ne puissent pas utiliser de fonctions anonymes.

37
user85109

Voici une autre option que vous pouvez utiliser. Créez d'abord un tableau de cellules pour capturer toutes les sorties (vous pouvez utiliser la fonction NARGOUT pour déterminer le nombre de sorties qu'une fonction donnée renvoie):

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

Appelez ensuite la fonction comme suit:

[a{:}] = func();

Il suffit ensuite de supprimer l'élément de a que vous souhaitez, et d'écraser a :

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

J'ai écrit une fonction 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

vous pouvez ensuite appeler

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

vous pouvez également terminer la fonction comme

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

après quoi vous utilisez

val_i_want = func_i_want(func_input_1,func_input_2);

notez qu'il y a des frais généraux associés à l'utilisation de fonctions anonymes comme celle-ci, et ce n'est pas quelque chose que je ferais dans du code qui serait appelé des milliers de fois.

9
shabbychef

Dans Matlab 2010a, j'ai trouvé une bonne façon de faire ce que vous demandez. Il s'agit simplement d'utiliser le characher "~" (sans les guillemets bien sûr) comme variable fictive (autant que vous le souhaitez lorsque vous retournez plusieurs paramètres). Cela fonctionne également pour les paramètres d'entrée des fonctions si les fonctions sont conçues pour gérer les données manquantes. Je ne sais pas si cela existait dans les versions précédentes, mais je l'ai rencontré récemment.

4
Sam

Vous pouvez créer une fonction (ou une fonction anonyme) qui ne renvoie que les sorties sélectionnées, par ex.

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

Ensuite, vous pouvez appeler votre fonction comme ceci:

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

Ou vous pouvez affecter la sortie à une variable:

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

Y a-t-il une raison de ne pas utiliser ans (n), comme ceci:

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

size(a);

b=ans(2);

Donne b = 10, et cette manière ne serait-elle pas compatible avec toutes les versions de Matlab?

De plus, cela fonctionne pour obtenir le deuxième argument de sortie lorsque vous ne savez pas combien d'arguments il y aura! Alors que si vous faites cela:

[~, b] = size(a);

Alors b = 8000! (Vous devez terminer par ~, pour attraper plus d'arguments!)

0
user1596274