Làm cách nào để bỏ qua một số giá trị trả về của hàm MATLAB một cách thanh lịch?


120

Có thể nhận giá trị trả về 'thứ n' từ một hàm mà không cần phải tạo biến giả cho tất cả các n-1giá trị trả về trước nó không?

Giả sử, tôi có hàm sau trong MATLAB:

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

Bây giờ, giả sử, tôi chỉ quan tâm đến giá trị trả về thứ ba . Điều này có thể được thực hiện bằng cách tạo một biến giả:

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

Nhưng tôi nghĩ đây là loại xấu xí . Tôi nghĩ rằng bạn có thể làm điều gì đó giống như một trong những điều sau đây, nhưng bạn không thể:

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

[, , variableThatIWillUse, ] = func;

variableThatIWillUse = func(3);

variableThatIWillUse = func()(3);

Có cách nào thanh lịch để làm điều này mà hiệu quả không?


Cho đến nay, giải pháp tốt nhất là chỉ cần sử dụng variableThatIWillUselàm biến giả. Điều này giúp tôi không phải tạo một biến giả thực gây ô nhiễm không gian làm việc (hoặc tôi cần phải xóa). Tóm lại: giải pháp là sử dụng variableThatIWillUsecho mọi giá trị trả về cho đến giá trị thú vị. Giá trị trả về sau khi có thể đơn giản bị bỏ qua:

[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;

Tôi vẫn nghĩ đây là mã rất xấu, nhưng nếu không có cách nào tốt hơn, thì tôi đoán tôi sẽ chấp nhận câu trả lời.


Ngoài việc sử dụng một mảng ô như tôi đã mô tả trong câu trả lời của mình, thì việc lặp lại tên biến có lẽ là giải pháp khác duy nhất của bạn. Hy vọng rằng tên biến của bạn không dài như "variableThatIWillUse". =)
gnovice

Trên thực tế là họ. 'dummy' chỉ là một ví dụ. Thông thường, tôi sẽ sử dụng 'variableThatIWillNotUse'. Các biến khác được đặt tên là 'variableThatIMightUse', 'variableThatIWillUse2' và 'variableThatCanBarelyFitOnA80CharacterLine'. Tôi đang nghiên cứu mối tương quan giữa những cái tên dài và xếp hạng giết người. ;)
Jordi

26
Trên thực tế, kể từ khi trả về hàm bỏ qua R2009b được giải quyết thanh lịch hơn bằng cách sử dụng '~' -Char. ví dụ: [~, b] = sort (rand (10,1))
ymihere

1
DÀNH CHO NGƯỜI MỚI ĐỌC: ^ phải là câu trả lời chính xác. Xem câu trả lời của ManWithSleeve bên dưới
A.Wan

1
Trong ví dụ của bạn, nếu bạn chỉ muốn đối số đầu ra thứ 3, bạn sẽ sử dụng: [variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func; Không cần phải xóa một biến giả. Đối với các phiên bản MATLAB mới hơn> = R2009b, hãy sử dụng [~, ~, variableThatIWillUse] = func;
Thierry Dalon

Câu trả lời:


38

Đây là một phần của một hack nhưng nó hoạt động:

Đầu tiên là một ví dụ nhanh về chức năng:

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

Bây giờ, mấu chốt ở đây là nếu bạn sử dụng một biến hai lần ở phía bên trái của phép gán nhiều biểu thức, thì phép gán trước đó sẽ bị che lấp bởi phép gán sau:

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

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

(chỉnh sửa: chỉ để kiểm tra, tôi cũng đã xác minh rằng kỹ thuật này hoạt động [mu,mu,mu]=polyfit(x,y,n)nếu tất cả những gì bạn quan tâm polyfitlà đối số thứ 3)


chỉnh sửa: có một cách tiếp cận tốt hơn; thay vào đó hãy xem câu trả lời của ManWithSleeve .


7
Đã không nghĩ về việc giải quyết nó như thế này. Tuy nhiên, tôi cảm thấy giải pháp này hy sinh sự rõ ràng của ý định cho sự khôn khéo.
Jukka Dahlbom

5
Cá nhân tôi chỉ sử dụng [junk, junk, c] = function_call () và giả định rằng "junk" không bao giờ là một biến quan trọng và nếu nó chứa nhiều bộ nhớ, tôi sẽ xóa nó nếu cần.
Jason S

5
cho người ủng hộ: Tại sao lại là -1? Câu trả lời này đã được viết trước khi R2009b thậm chí được phát hành, vì vậy câu trả lời của @ ManWithSleeve sẽ không hoạt động vào thời điểm đó. Tất nhiên, đó là cách tiếp cận đúng đắn.
Jason S

2
Có thể một bình luận ở dòng đầu tiên của câu trả lời của bạn sẽ hữu ích? Tôi mới đến đây thông qua google, vì vậy có vẻ như nó đáng để cập nhật.
FvD

Phép gán từ trái sang phải không được The MathWorks đảm bảo chính thức, vì vậy có lẽ bạn không nên dựa vào việc sử dụng c sau [c, c, c] = myFunc (). (Xem Bình luận # 26 tại đây: blogs.mathworks.com/loren/2009/09/11/… )
Matt Krause

226

Với MATLAB Phiên bản 7.9 (R2009b), bạn có thể sử dụng dấu ~, ví dụ:

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

Lưu ý rằng ,không phải là tùy chọn. Chỉ cần gõ [~ ~ var]sẽ không hoạt động và sẽ xuất hiện lỗi.

Xem ghi chú phát hành để biết chi tiết.


3
Hơi khó chịu khi nó không phải là "_". (Tôi cho rằng nó đã được thực hiện rồi?)
SamB 14/09/10

4
@SamB: mặc dù sử dụng các nottoán tử như trong don't carekhông phải là xấu cả
Tobias KIENZLER

28
Lưu ý rằng ,không phải là tùy chọn. Chỉ cần gõ [~ ~ var]sẽ không hoạt động và sẽ xuất hiện lỗi.
eykanal,

Tôi sẽ nói rằng đây là câu trả lời "chính xác". Còn lại chỉ là những bản hack để khắc phục sự cố không tồn tại. Mặc dù vậy, không có ý định chơi chữ nào cả ...
Patrick

6
Câu hỏi được đặt ra vào năm 2009 trước R2009b, tại thời điểm đó ~ không hoạt động.
Tom Anderson

37

Nếu bạn muốn sử dụng một kiểu mà một biến sẽ được để lại trong bit bucket, thì một giải pháp thay thế hợp lý là

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

ans tất nhiên là biến rác mặc định cho matlab, thường xuyên bị ghi đè trong phiên.

Mặc dù tôi thích thủ thuật mới mà MATLAB hiện cho phép, sử dụng dấu ~ để chỉ định một biến trả về bị bỏ qua, đây là một vấn đề đối với khả năng tương thích ngược, trong đó người dùng các bản phát hành cũ hơn sẽ không thể sử dụng mã của bạn. Tôi thường tránh sử dụng những thứ mới như vậy cho đến khi có ít nhất một vài bản phát hành MATLAB được phát hành để đảm bảo rằng sẽ có rất ít người dùng còn lại trong tình trạng chao đảo. Ví dụ: ngay cả bây giờ tôi thấy mọi người vẫn đang sử dụng bản phát hành MATLAB đủ cũ mà họ không thể sử dụng các chức năng ẩn danh.


7
Vâng, nó rất thông minh, nhưng trình soạn thảo Matlab gốc sẽ đưa ra cảnh báo nếu bạn gán bất kỳ thứ gì cho biến ans. Tôi không nghĩ rằng có cảnh báo là rất thanh lịch ...
Jordi

11
Bạn có thể tắt cảnh báo. Kết thúc dòng bằng chuỗi nhận xét này% # ok Sau đó Mlint sẽ bỏ qua điều này. Không có cảnh báo.

13

Đây là một tùy chọn khác mà bạn có thể sử dụng. Đầu tiên hãy tạo một mảng ô để nắm bắt tất cả các kết quả đầu ra (bạn có thể sử dụng hàm NARGOUT để xác định có bao nhiêu kết quả đầu ra mà một hàm đã cho trả về):

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

Sau đó gọi hàm như sau:

[a{:}] = func();

Sau đó, chỉ cần xóa phần tử khỏi một phần tử mà bạn muốn và ghi đè lên một :

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

9

Tôi đã viết một hàm ra thứ k:


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

sau đó bạn có thể gọi

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

bạn cũng có thể tóm tắt chức năng như

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

sau đó bạn sử dụng

val_i_want = func_i_want(func_input_1,func_input_2);

lưu ý rằng có chi phí liên quan đến việc sử dụng các hàm ẩn danh như thế này và đây không phải là điều tôi sẽ làm trong mã sẽ được gọi hàng nghìn lần.


4

Trong Matlab 2010a, tôi đã tìm thấy một cách gọn gàng để thực hiện những gì bạn đang yêu cầu. Nó chỉ đơn giản là sử dụng characher "~" (tất nhiên không có dấu ngoặc kép) làm biến giả của bạn (bao nhiêu tùy thích khi trả về nhiều tham số). Điều này cũng hoạt động đối với các tham số đầu vào cho các hàm nếu các hàm được thiết kế để xử lý dữ liệu bị thiếu. Tôi không biết liệu điều này có tồn tại trong các phiên bản trước hay không, nhưng tôi chỉ mới xem qua nó gần đây.


11
Bạn không thấy câu trả lời trước?
yuk

1

Bạn có thể tạo một hàm (hoặc hàm ẩn danh) chỉ trả về các đầu ra đã chọn, ví dụ:

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

Sau đó, bạn có thể gọi hàm của mình như sau:

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

Hoặc bạn có thể gán đầu ra cho một biến:

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

không làm việc cho tôi. Đã thửdecimatedfftx = select(fft(x,12),1:4:12);
NotGaeL

1
select(func,2)cuộc gọi func(2). Tôi không thấy nơi điều này chọn đối số đầu ra.
Cris Luengo

0

Có lý do gì để không sử dụng ans (n), như sau:

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

size(a);

b=ans(2);

Cho b = 10, và cách này sẽ không tương thích với tất cả các phiên bản Matlab?

Hơn nữa, điều này hoạt động để lấy đối số đầu ra thứ hai khi bạn không biết sẽ có bao nhiêu đối số! Trong khi, nếu bạn làm điều này:

[~, b] = size(a);

Khi đó b = 8000! (Bạn cần kết thúc bằng ~, để bắt thêm đối số!)


Câu trả lời này giả sử biến được trả về là một vectơ, điều này có thể không phải là ý của OP.
Neil Traft

Điều này không có ý nghĩa. size(a)[b,c]=size(a)trả lại những thứ khác nhau. Các hàm trong MATLAB thay đổi hành vi dựa trên số lượng đối số đầu ra.
Cris Luengo

Tôi đang rất khó hiểu câu trả lời này. Tôi không biết điều này góp phần vào chất lượng của các câu trả lời ở đây như thế nào, chứ đừng nói là điều này không trực tiếp trả lời câu hỏi ban đầu.
rayryeng

Đã 6 năm sau, và tôi không còn sử dụng Matlab nữa. Theo như tôi nhớ, hàm "size ()" không liên quan - tôi chỉ sử dụng nó như một hàm trả về nhiều đối số. Vấn đề là tôi có thể chỉ cần gọi hàm func () và sau đó là ans (n) để nhận giá trị của số biến trả về n. Điều này dường như hoạt động tốt cho một số tình huống nhất định và tương thích ngược. Tất nhiên, nó chỉ có thể hoạt động với một số hàm nhất định hoặc các kiểu biến, bất cứ điều gì. Đó là chừng nào tôi có thể giúp 6 năm sau.
user1596274
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.