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

120

Est-il possible d'obtenir la «nième» valeur de retour d'une fonction sans avoir à créer des variables fictives pour toutes les n-1valeurs de retour 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 m'intéresse qu'à la troisième valeur de retour. Cela peut être accompli en créant une variable factice:

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

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

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

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Y a-t-il des façons élégantes de faire cela qui fonctionnent?


Jusqu'à présent, la meilleure solution consiste simplement à utiliser le variableThatIWillUsecomme variable factice. Cela m'évite d'avoir à créer une vraie variable factice qui pollue l'espace de travail (ou que j'aurais besoin d'effacer). En bref: la solution est d'utiliser le variableThatIWillUsepour chaque valeur de retour jusqu'à l'intéressante. Les valeurs renvoyées après peuvent simplement être ignorées:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

Je pense toujours que c'est un code très laid, mais s'il n'y a pas de meilleur moyen, je suppose que j'accepterai la réponse.

Jordi
la source
En plus d'utiliser un tableau de cellules comme je l'ai décrit dans ma réponse, répéter le nom de la variable est probablement votre seule autre solution. Espérons que vos noms de variables ne sont pas aussi longs que "variableThatIWillUse". =)
gnovice
En fait, ils le sont. «factice» n'était qu'un exemple. Normalement, j'utiliserais «variableThatIWillNotUse». Les autres variables sont nommées «variableThatIMightUse», «variableThatIWillUse2» et «variableThatCanBarelyFitOnA80CharacterLine». Je recherche la corrélation entre les noms longs et les classements d'homicides. ;)
Jordi
26
En fait, depuis R2009b, ignorer les retours de fonction est résolu plus élégamment en utilisant le '~' -Char. par exemple: [~, b] = sort (rand (10,1))
ymihere
1
POUR LES NOUVEAUX LECTEURS: ^ devrait être la bonne réponse. Voir la réponse de ManWithSleeve ci
A.Wan
1
Dans votre exemple, si vous ne voulez que le 3ème argument de sortie, vous devez utiliser: [variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func; Pas besoin d'effacer une variable factice. Pour les versions plus récentes de MATLAB> = R2009b, utilisez [~, ~, variableThatIWillUse] = func;
Thierry Dalon

Réponses:

38

C'est un peu un hack mais cela fonctionne:

Tout 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 la partie gauche d'une affectation à expressions multiples, une affectation antérieure est écrasée par l'affectation ultérieure:

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

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

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


edit: il y a une meilleure approche; voir plutôt la réponse de ManWithSleeve .

Jason S
la source
7
Je n'avais pas pensé à le résoudre comme ça. Cependant, je pense que cette solution sacrifie la clarté de l'intention au profit de l'intelligence.
Jukka Dahlbom
5
Personnellement, j'utilise simplement [junk, junk, c] = function_call () et suppose à la fois que "junk" n'est jamais une variable importante et que s'il contient beaucoup de mémoire, je l'effacerai si nécessaire.
Jason S
5
à l'électeur négatif: pourquoi le -1? Cette réponse a été écrite avant même la sortie de R2009b, donc la réponse de @ ManWithSleeve n'aurait pas fonctionné à l'époque. Maintenant, bien sûr, c'est la bonne approche.
Jason S
2
Peut-être qu'un commentaire dans la première ligne de votre réponse serait utile? Je viens de venir ici via google, donc il semble que cela vaut la peine d'être mis à jour.
FvD
L'affectation de gauche à droite n'est pas officiellement garantie par The MathWorks, donc vous ne devriez probablement pas vous fier à l'utilisation de c après [c, c, c] = myFunc (). (Voir le commentaire n ° 26 ici: blogs.mathworks.com/loren/2009/09/11/… )
Matt Krause
226

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

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

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

Consultez les notes de version pour plus de détails.

HommeAvecSleeve
la source
3
Un peu ennuyeux que ce ne soit pas "_". (Je suppose que cela a déjà été pris?)
SamB
4
@SamB: bien que l'utilisation de l' notopérateur comme dans don't carene soit pas si mal non plus
Tobias Kienzler
28
Notez que le ,n'est pas facultatif. Il suffit de taper [~ ~ var]sera pas le travail, et sera une erreur.
eykanal
Je dirais que c'est la «bonne» réponse. Les autres ne sont que des hacks pour résoudre un problème qui n'existe pas. Pas de jeu de mots cependant ...
patrik
6
La question a été posée en 2009 avant R2009b, date à laquelle le ~ ne fonctionnait pas.
Tom Anderson
37

Si vous souhaitez utiliser un style dans lequel une variable sera laissée tomber dans le seau de bits, une alternative raisonnable est

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

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

Bien que j'aime la nouvelle astuce que MATLAB permet maintenant, en utilisant un ~ pour désigner une variable de retour ignorée, c'est un problème de compatibilité descendante, en ce sens que les utilisateurs d'anciennes versions 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 m'assurer qu'il restera très peu d'utilisateurs dans l'embarras. 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.


la source
7
Oui, c'est intelligent, mais l'éditeur natif de Matlab donnera un avertissement si vous attribuez quelque chose à la variable ans. Je ne pense pas qu'avoir des avertissements soit très élégant ...
Jordi
11
Vous pouvez désactiver l'avertissement. Terminez la ligne avec cette chaîne de commentaire% # ok Mlint l'ignorera alors. Aucun avertissement.
13

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 renvoyées par une fonction donnée):

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

Ensuite, supprimez simplement l'élément de a que vous voulez et écrasez a :

a = a{3};  % Get the third output
novice
la source
9

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 alors 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 une surcharge associée à l'utilisation de fonctions anonymes comme celle-ci, et ce n'est pas quelque chose que je ferais dans un code qui serait appelé des milliers de fois.

shabbychef
la source
4

Dans Matlab 2010a, j'ai trouvé une manière intéressante de faire ce que vous demandez. Il s'agit simplement d'utiliser le characher "~" (sans les guillemets bien sûr) comme variable factice (autant que vous le souhaitez lors du retour de 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 suis juste tombé dessus récemment.

Sam
la source
11
Vous n'avez pas vu la réponse précédente?
yuk
1

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

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);
Dave
la source
ne fonctionne pas pour moi. Essayédecimatedfftx = select(fft(x,12),1:4:12);
NotGaeL
1
select(func,2)appels func(2). Je ne vois pas où cela sélectionne les arguments de sortie.
Cris Luengo
0

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 façon 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 ceci:

[~, b] = size(a);

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

user1596274
la source
Cette réponse suppose que la variable renvoyée est un vecteur, ce qui n'était probablement pas ce que l'OP signifiait.
Neil Traft
Cela n'a aucun sens. size(a)et [b,c]=size(a)renvoyer des choses différentes. Les fonctions de MATLAB changent de comportement en fonction du nombre d'arguments de sortie.
Cris Luengo
J'ai du mal à comprendre cette réponse. Je ne sais pas comment cela contribue à la qualité des réponses ici, encore moins que cela ne répond pas directement à la question initiale.
rayryeng
C'est 6 ans plus tard, et je n'utilise plus Matlab. Autant que je me souvienne, la fonction "size ()" n'était pas pertinente - je l'ai juste utilisée comme une fonction qui retournerait plusieurs arguments. Le fait est que je peux simplement appeler func () puis ans (n) pour obtenir la valeur de la variable numéro n renvoyée. Cela semble bien fonctionner dans certaines situations et être rétrocompatible. Il ne peut fonctionner qu'avec certaines fonctions bien sûr, ou des types de variables, peu importe. C'est tout ce que je peux aider 6 ans plus tard.
user1596274