Come ignorare elegantemente alcuni valori di ritorno di una funzione MATLAB?


120

È possibile ottenere l'ennesimo valore di ritorno da una funzione senza dover creare variabili fittizie per tutti i n-1valori di ritorno precedenti?

Diciamo, ho la seguente funzione in MATLAB:

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

Supponiamo ora che mi interessi solo il terzo valore di ritorno. Questo può essere ottenuto creando una variabile fittizia:

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

Ma penso che questo sia un po ' brutto . Penso che potresti essere in grado di fare qualcosa come una delle seguenti cose, ma non puoi:

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

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Ci sono modi eleganti per farlo che funzionano?


Finora, la soluzione migliore è usare semplicemente variableThatIWillUsecome variabile fittizia. Questo mi evita di dover creare una vera e propria variabile fittizia che inquina lo spazio di lavoro (o che avrei bisogno di cancellare). In breve: la soluzione è utilizzare il variableThatIWillUsevalore di ritorno for every fino a quello interessante. I valori restituiti dopo possono essere semplicemente ignorati:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

Penso ancora che questo sia un codice molto brutto, ma se non esiste un modo migliore, immagino che accetterò la risposta.


Oltre a utilizzare un array di celle come ho descritto nella mia risposta, ripetere il nome della variabile è probabilmente l'unica altra soluzione. Si spera che i nomi delle variabili non siano lunghi quanto "variableThatIWillUse". =)
gnovice

In realtà lo sono. "dummy" era solo un esempio. Normalmente userei 'variableThatIWillNotUse'. Altre variabili sono denominate "variableThatIMightUse", "variableThatIWillUse2" e "variableThatCanBarelyFitOnA80CharacterLine". Sto ricercando la correlazione tra nomi lunghi e valutazioni di omicidi. ;)
Jordi

26
In realtà, poiché R2009b ignorare i ritorni di funzione viene risolto in modo più elegante utilizzando il carattere "~". ad esempio: [~, b] = sort (rand (10,1))
ymihere

1
PER I NUOVI LETTORI: ^ dovrebbe essere la risposta corretta. Vedi la risposta di ManWithSleeve di seguito
A.Wan

1
Nel tuo esempio, se vuoi solo il terzo argomento di output, devi usare: [variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func; Non è necessario cancellare una variabile fittizia. Per le versioni MATLAB più recenti> = R2009b, usa [~, ~, variableThatIWillUse] = func;
Thierry Dalon

Risposte:


38

Questo è un po 'un trucco ma funziona:

Innanzitutto un rapido esempio di funzione:

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

Ora la chiave qui è che se usi una variabile due volte sul lato sinistro di un assegnamento di espressioni multiple, un assegnamento precedente viene cancellato dall'assegnazione successiva:

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

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

(modifica: solo per verificare, ho anche verificato che questa tecnica funzioni [mu,mu,mu]=polyfit(x,y,n)se tutto ciò che ti interessa polyfitè il 3 ° argomento)


modifica: c'è un approccio migliore; vedi invece la risposta di ManWithSleeve .


7
Non avevo pensato di risolverlo in questo modo. Tuttavia, sento che questa soluzione sacrifica la chiarezza di intenti a favore dell'intelligenza.
Jukka Dahlbom

5
Personalmente uso solo [junk, junk, c] = function_call () e presumo che "junk" non sia mai una variabile importante e se contiene molta memoria la cancellerò se necessario.
Jason S

5
al downvoter: Perché -1? Questa risposta è stata scritta prima ancora che R2009b fosse rilasciato, quindi la risposta di @ ManWithSleeve non avrebbe funzionato in quel momento. Ora, ovviamente, questo è l'approccio giusto.
Jason S,

2
Forse un commento nella prima riga della tua risposta sarebbe utile? Sono appena arrivato qui tramite Google, quindi sembra che valga la pena aggiornarlo.
FvD

L'assegnazione da sinistra a destra non è ufficialmente garantita da The MathWorks, quindi probabilmente non dovresti fare affidamento sull'uso di c dopo [c, c, c] = myFunc (). (Vedi commento # 26 qui: blogs.mathworks.com/loren/2009/09/11/… )
Matt Krause

226

Con MATLAB versione 7.9 (R2009b) puoi usare un ~, ad es.

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

Nota che ,non è opzionale. La semplice digitazione [~ ~ var]non funzionerà e genererà un errore.

Vedere le note sulla versione per i dettagli.


3
Un po 'fastidioso che non sia "_". (Suppongo che sia già stato preso?)
SamB

4
@SamB: anche se usare l' notoperatore come in don't carenon è poi così male
Tobias Kienzler

28
Tieni presente che ,non è opzionale. Tipizzazione appena [~ ~ var]sarà non lavoro e genera un errore.
eykanal

Direi che questa è la risposta "corretta". Gli altri sono solo degli hack per risolvere un problema che non esiste. Nessun gioco di parole però ...
patrik

6
La domanda è stata posta nel 2009 prima dell'R2009b, momento in cui ~ non ha funzionato.
Tom Anderson

37

Se desideri utilizzare uno stile in cui una variabile verrà lasciata cadere nel secchio di bit, allora un'alternativa ragionevole è

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

ans è ovviamente la variabile spazzatura predefinita per matlab, che viene spesso sovrascritta nel corso di una sessione.

Anche se mi piace il nuovo trucco che MATLAB ora consente, utilizzando un ~ per designare una variabile di ritorno ignorata, questo è un problema per la retrocompatibilità, in quanto gli utenti di versioni precedenti non saranno in grado di utilizzare il tuo codice. In genere evito di usare cose nuove del genere fino a quando non sono state rilasciate almeno alcune versioni di MATLAB per assicurarmi che rimarranno pochissimi utenti nel gioco. Ad esempio, anche ora trovo che le persone stiano ancora utilizzando una versione MATLAB abbastanza vecchia da non poter utilizzare funzioni anonime.


7
Sì, è intelligente, ma l'editor Matlab nativo darà un avviso se assegni qualcosa alla variabile ans. Non credo che avere degli avvertimenti sia molto elegante ...
Jordi

11
Puoi disattivare l'avviso. Termina la riga con questa stringa di commento% # ok Mlint lo ignorerà. Nessun avviso.

13

Ecco un'altra opzione che puoi usare. Per prima cosa crea un array di celle per catturare tutti gli output (puoi usare la funzione NARGOUT per determinare quanti output restituisce una determinata funzione):

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

Quindi chiama la funzione come segue:

[a{:}] = func();

Quindi rimuovi semplicemente l'elemento da un che desideri e sovrascrivi un :

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

9

Ho scritto una funzione 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

puoi quindi chiamare

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

potresti anche concludere la funzione come

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

dopo di che usi

val_i_want = func_i_want(func_input_1,func_input_2);

nota che c'è un sovraccarico associato all'uso di funzioni anonime come questa, e questo non è qualcosa che farei nel codice che verrebbe chiamato migliaia di volte.


4

In Matlab 2010a, ho trovato un modo accurato per fare ciò che chiedi. Si tratta semplicemente di utilizzare il carattere "~" (senza virgolette ovviamente) come variabile fittizia (quante ne vuoi quando restituisci più parametri). Questo funziona anche per i parametri di input alle funzioni se le funzioni sono progettate per gestire i dati mancanti. Non so se esistesse nelle versioni precedenti, ma l'ho scoperto di recente.


11
Non hai visto la risposta precedente?
yuk

1

È possibile creare una funzione (o una funzione anonima) che restituisca solo output selezionati, ad es

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

Quindi puoi chiamare la tua funzione in questo modo:

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

Oppure puoi assegnare l'output a una variabile:

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

non funziona per me. Provatodecimatedfftx = select(fft(x,12),1:4:12);
NotGaeL

1
select(func,2)chiamate func(2). Non vedo dove questo seleziona gli argomenti di output.
Cris Luengo

0

C'è qualche motivo per non usare ans (n), in questo modo:

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

size(a);

b=ans(2);

Fornisce b = 10 e in questo modo non sarebbe compatibile con tutte le versioni di Matlab?

Inoltre, funziona per ottenere il secondo argomento di output quando non sai quanti argomenti ci saranno! Considerando che, se lo fai:

[~, b] = size(a);

Allora b = 8000! (Devi terminare con ~, per catturare più argomenti!)


Questa risposta presuppone che la variabile restituita sia un vettore, che probabilmente non era ciò che intendeva l'OP.
Neil Traft

Questo non ha senso. size(a)e [b,c]=size(a)restituire cose diverse. Le funzioni in MATLAB cambiano il comportamento in base al numero di argomenti di output.
Cris Luengo

Faccio fatica a capire questa risposta. Non so come questo contribuisca alla qualità delle risposte qui, per non parlare del fatto che questo non risponde direttamente alla domanda originale.
rayryeng

Sono passati 6 anni e non uso più Matlab. Per quanto ricordo, la funzione "size ()" era irrilevante: l'ho usata semplicemente come una funzione che restituiva più argomenti. Il punto è che posso semplicemente chiamare func () e poi ans (n) per ottenere il valore della variabile restituita numero n. Sembrava funzionare bene per determinate situazioni ed essere retrocompatibile. Può funzionare solo con determinate funzioni, naturalmente, o tipi di variabili, qualunque sia. Questo è quanto posso aiutare 6 anni dopo.
user1596274
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.