Bagaimana cara secara elegan mengabaikan beberapa nilai kembali dari fungsi MATLAB?


120

Apakah mungkin untuk mendapatkan nilai kembalian 'n' dari suatu fungsi tanpa harus membuat variabel dummy untuk semua n-1nilai kembalian sebelumnya?

Katakanlah, saya memiliki fungsi berikut di MATLAB:

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

Sekarang misalkan, saya hanya tertarik pada nilai pengembalian ketiga . Ini dapat dilakukan dengan membuat satu variabel dummy:

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

Tapi saya pikir ini agak jelek . Menurut saya, Anda mungkin dapat melakukan sesuatu seperti salah satu dari hal-hal berikut, tetapi Anda tidak dapat:

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

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Adakah cara elegan untuk melakukan ini yang berhasil?


Sejauh ini, solusi terbaik adalah dengan hanya menggunakan variableThatIWillUsevariabel dummy. Ini menyelamatkan saya dari keharusan membuat variabel dummy nyata yang mencemari ruang kerja (atau yang perlu saya bersihkan). Singkatnya: solusinya adalah menggunakan variableThatIWillUsefor setiap nilai pengembalian hingga nilai yang menarik. Kembalikan nilai setelah dapat dengan mudah diabaikan:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

Saya masih berpikir ini adalah kode yang sangat jelek, tetapi jika tidak ada cara yang lebih baik, maka saya kira saya akan menerima jawabannya.


Selain menggunakan array sel seperti yang saya jelaskan dalam jawaban saya, mengulangi nama variabel mungkin satu-satunya solusi Anda yang lain. Mudah-mudahan nama variabel Anda tidak sepanjang "variableThatIWillUse". =)
gnovice

Sebenarnya mereka. 'dummy' hanyalah sebuah contoh. Biasanya saya akan menggunakan 'variableThatIWillNotUse'. Variabel lain diberi nama 'variableThatIMightUse', 'variableThatIWillUse2' dan 'variableThatCanBarelyFitOnA80CharacterLine'. Saya sedang meneliti korelasi antara nama panjang dan peringkat pembunuhan. ;)
Jordi

26
Sebenarnya sejak R2009b mengabaikan pengembalian fungsi diselesaikan dengan lebih elegan menggunakan '~' -Char. misalnya: [~, b] = sort (rand (10,1))
ymihere

1
UNTUK PEMBACA BARU: ^ harus menjadi jawaban yang benar. Lihat jawaban ManWithSleeve di bawah
A.Wan

1
Dalam contoh Anda jika Anda hanya ingin argumen keluaran ke-3 Anda harus menggunakan: [variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func; Tidak perlu menghapus variabel dummy. Untuk versi MATLAB yang lebih baru> = R2009b, gunakan [~, ~, variableThatIWillUse] = func;
Thierry Dalon

Jawaban:


38

Ini agak retas tetapi berhasil:

Pertama, fungsi contoh cepat:

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

Sekarang kuncinya di sini adalah jika Anda menggunakan variabel dua kali di sisi kiri dari tugas ekspresi ganda, tugas sebelumnya dikalahkan oleh tugas selanjutnya:

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

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

(edit: hanya untuk memeriksa, saya juga memverifikasi bahwa teknik ini berfungsi [mu,mu,mu]=polyfit(x,y,n)jika semua yang Anda pedulikan polyfitadalah argumen ke-3)


edit: ada pendekatan yang lebih baik; lihat jawaban ManWithSleeve .


7
Belum terpikir untuk menyelesaikannya seperti ini. Namun, saya merasa solusi ini mengorbankan kejelasan niat untuk kepintaran.
Jukka Dahlbom

5
Saya pribadi hanya menggunakan [junk, junk, c] = function_call () dan menganggap bahwa "junk" tidak pernah menjadi variabel penting dan jika mengandung banyak memori, saya akan menghapusnya jika perlu.
Jason S

5
ke downvoter: Mengapa -1? Jawaban ini ditulis bahkan sebelum R2009b dirilis, jadi jawaban @ ManWithSleeve tidak akan berfungsi pada saat itu. Nah, tentu saja, itu pendekatan yang tepat.
Jason S

2
Mungkin komentar di baris pertama jawaban Anda bisa membantu? Saya baru saja datang ke sini melalui google, jadi sepertinya perlu diperbarui.
FvD

Penugasan kiri-ke-kanan tidak secara resmi dijamin oleh The MathWorks, jadi Anda sebaiknya tidak mengandalkan penggunaan c setelah [c, c, c] = myFunc (). (Lihat Komentar # 26 di sini: blogs.mathworks.com/loren/2009/09/11/… )
Matt Krause

226

Dengan MATLAB Versi 7.9 (R2009b) Anda dapat menggunakan ~, misalnya,

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

Perhatikan bahwa ,ini bukan opsional. Hanya mengetik [~ ~ var]tidak akan berhasil, dan akan menimbulkan kesalahan.

Lihat catatan rilis untuk detailnya.


3
Agak menjengkelkan karena itu bukan "_". (Saya kira itu sudah diambil?)
SamB

4
@ SamB: meskipun menggunakan notoperator seperti don't careini juga tidak terlalu buruk
Tobias Kienzler

28
Perhatikan bahwa ,ini bukan opsional. Hanya mengetik tidak[~ ~ var] akan berhasil, dan akan menimbulkan kesalahan.
eykanal

Saya akan mengatakan bahwa ini adalah jawaban yang "benar". Yang lainnya hanyalah peretasan untuk memperbaiki masalah yang tidak ada. Tidak ada pelesetan meskipun ...
patrik

6
Pertanyaan tersebut diajukan pada tahun 2009 sebelum R2009b, di mana pada saat itu ~ tidak berhasil.
Tom Anderson

37

Jika Anda ingin menggunakan gaya di mana variabel akan dibiarkan jatuh ke keranjang bit, maka alternatif yang masuk akal adalah

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

ans tentu saja merupakan variabel sampah default untuk matlab, sering ditimpa selama sesi.

Sementara saya menyukai trik baru yang sekarang memungkinkan MATLAB, menggunakan ~ untuk menunjuk variabel pengembalian yang diabaikan, ini adalah masalah kompatibilitas mundur, karena pengguna rilis lama tidak akan dapat menggunakan kode Anda. Saya biasanya menghindari menggunakan hal-hal baru seperti itu sampai setidaknya beberapa rilis MATLAB telah dikeluarkan untuk memastikan akan ada sangat sedikit pengguna yang tersisa dalam kesulitan. Misalnya, bahkan sekarang saya menemukan orang-orang masih menggunakan rilis MATLAB yang cukup lama sehingga mereka tidak dapat menggunakan fungsi anonim.


7
Ya, ini pintar, tetapi editor Matlab asli akan memberikan peringatan jika Anda menetapkan sesuatu ke variabel ans. Saya tidak berpikir memiliki peringatan itu sangat elegan ...
Jordi

11
Anda bisa mematikan peringatan. Akhiri baris dengan string komentar ini% # ok Mlint akan mengabaikan ini. Tidak ada peringatan.

13

Berikut opsi lain yang dapat Anda gunakan. Pertama buat larik sel untuk menangkap semua keluaran (Anda dapat menggunakan fungsi NARGOUT untuk menentukan berapa banyak keluaran yang dikembalikan oleh fungsi tertentu):

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

Kemudian panggil fungsinya sebagai berikut:

[a{:}] = func();

Kemudian hanya menghapus elemen dari suatu yang Anda inginkan, dan menimpa sebuah :

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

9

Saya menulis fungsi 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

Anda kemudian dapat menelepon

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

Anda juga bisa menyelesaikan fungsi seperti

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

setelah itu Anda gunakan

val_i_want = func_i_want(func_input_1,func_input_2);

perhatikan bahwa ada overhead yang terkait dengan penggunaan fungsi anonim seperti ini, dan ini bukan sesuatu yang akan saya lakukan dalam kode yang akan dipanggil ribuan kali.


4

Di Matlab 2010a, saya menemukan cara yang rapi untuk melakukan apa yang Anda minta. Ini hanya dengan menggunakan karakter "~" (tanpa tanda kutip tentunya) sebagai variabel dummy Anda (sebanyak yang Anda inginkan saat mengembalikan beberapa parameter). Ini juga berfungsi untuk parameter masukan agar berfungsi jika fungsi dirancang untuk menangani data yang hilang. Saya tidak tahu apakah ini ada di versi sebelumnya, tetapi saya baru saja menemukannya baru-baru ini.


11
Apakah Anda tidak melihat jawaban sebelumnya?
yuk

1

Anda dapat membuat fungsi (atau fungsi anonim) yang hanya mengembalikan keluaran yang dipilih, mis

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

Kemudian Anda dapat memanggil fungsi Anda seperti ini:

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

Atau Anda dapat menetapkan output ke variabel:

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

tidak bekerja untuk saya. Mencobadecimatedfftx = select(fft(x,12),1:4:12);
NotGaeL

1
select(func,2)panggilan func(2). Saya tidak melihat di mana ini memilih argumen keluaran.
Cris Luengo

0

Apakah ada alasan untuk tidak menggunakan ans (n), seperti ini:

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

size(a);

b=ans(2);

Memberikan b = 10, dan apakah cara ini tidak kompatibel dengan semua versi Matlab?

Selain itu, ini berfungsi untuk mendapatkan argumen keluaran kedua ketika Anda tidak tahu berapa banyak argumen yang ada! Sedangkan jika Anda melakukan ini:

[~, b] = size(a);

Maka b = 8000! (Anda harus mengakhirinya dengan ~, untuk menangkap lebih banyak argumen!)


Jawaban ini mengasumsikan variabel yang dikembalikan adalah vektor, yang mungkin bukan yang dimaksud OP.
Neil Traft

Ini tidak masuk akal. size(a)dan [b,c]=size(a)mengembalikan hal yang berbeda. Fungsi dalam MATLAB mengubah perilaku berdasarkan jumlah argumen keluaran.
Cris Luengo

Saya kesulitan memahami jawaban ini. Saya tidak tahu bagaimana ini berkontribusi pada kualitas jawaban di sini, apalagi ini tidak langsung menjawab pertanyaan asli.
rayryeng

Ini 6 tahun kemudian, dan saya tidak lagi menggunakan Matlab. Sejauh yang saya ingat, fungsi "size ()" tidak relevan - saya hanya menggunakannya sebagai fungsi yang akan mengembalikan banyak argumen. Intinya adalah saya cukup memanggil func () dan kemudian ans (n) untuk mendapatkan nilai variabel yang dikembalikan nomor n. Ini tampaknya bekerja dengan baik untuk situasi tertentu dan kompatibel ke belakang. Ini mungkin hanya bekerja dengan fungsi tertentu saja, atau tipe variabel, apapun. Itu sebanyak yang bisa saya bantu 6 tahun kemudian.
pengguna1596274
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.