Elegantly refer to the second output from a function

조회 수: 221 (최근 30일)
Xin
Xin 2018년 2월 9일
댓글: jessupj 2023년 12월 12일
Hello everyone. I have a function (matlab function, say "ismember") and I want to use the second output from this function as index in a vector. For example:
data = rand(1,10);
[A,B] = ismember(1,[0,1,2,3,4,5]);
result = data(B);
My question is how do I skip the second line and directly use B in line 3.
Many thanks

답변 (8개)

Hank
Hank 2020년 2월 6일
편집: Hank 2020년 2월 6일
I wrote two or three functions that allow me to do this. I agree, its much nicer to be able to one line certain values from builtin functions. I hate writing
[~,~,extension] = fileparts( file );
[~,imax] = max(x);
When i want to use extension or imax directly in a statement. So put these functions in your path:
function out = out2(fun) % gets the second output argument of anonymous function fun
[~,out] = fun(); % fun must have no input arguments
end
function out = out3(fun) % gets third
[~,~,out] = fun();
end
% make a function for 4 or 5 or however many output arguments you have!
Then call these with
ext = out3(@() fileparts(file));
imax = out2(@() max(x));
Note whats happening here is that you're wrapping up your original function call in an anonymous function with no arguments. Then this gets called inside the outN function and the correct output argument is returned.
The syntax is a little more clunky, but hey, its one line, it allows something like:
switch out3(@() fileparts(file))
case '.csv'; % csv stuff
case '.txt'; % txt stuff
end
  댓글 수: 2
Stephen23
Stephen23 2020년 2월 6일
편집: Stephen23 2020년 2월 6일
See also this FEX submission, which is one function that selects any output argument/s and does not require an anonymous function (just a simple function handle):
Charles Daigle
Charles Daigle 2023년 3월 23일
what a silly way to say that this feature is not supported

댓글을 달려면 로그인하십시오.


Jeremy
Jeremy 2022년 8월 22일
none of these proved the requested solution. MATLAB is a command line environement. Not being able to call a specific argument from a function makes the programming more expanded. This really should be a option for all function calls.
Why not just use the solutions mentioned?
  1. As stated, it requires multple command line executions or a wrapper function that would be unnecssary if this was available by default
  2. If the comman [~,X,~,~]=func(A,B,C) has to be called in an m file just to be able to use X, X is now stored in the workspace
  3. If a funciton has to be writted to wrap "func", X has to be computed in func, returned by func then returned by the wrapper function, so inherently less effecient.
  댓글 수: 2
gotjen
gotjen 2022년 8월 22일
Okay but
  1. Yes, this is the probelm we're trying to solve
  2. Yes, this is the problem we're trying to solve
  3. Returning a result from a nested function is not as time-expensive as you think it is. Even though its seems more theoretically convoluted, computationally its VERY fast.
Walter Roberson
Walter Roberson 2022년 8월 22일
None of them provide the requested solution because MATLAB does not support the requested functionality.

댓글을 달려면 로그인하십시오.


Arlon
Arlon 2023년 11월 7일
function ab=wrapTwo(f,varargin)
[a,b]=f(varargin{:});
ab={a,b};
end
extractACell=@(index,cell_array) cell_array{index};
data = rand(1,10)
result = data(extractACell(2,wrapTwo(@ismember,1,[0,1,2,3,4,5])))
  댓글 수: 1
Arlon
Arlon 2023년 12월 2일
편집: Arlon 2023년 12월 2일
See Matt J's solution which is superior to what I posted here, his is the correct answer and does what the OP requested.

댓글을 달려면 로그인하십시오.


Matt J
Matt J 2023년 11월 7일
편집: Matt J 2023년 11월 7일
data = (1:8)*100
data = 1×8
100 200 300 400 500 600 700 800
result = data( argEval(2,@ismember,1, [0,1,2,3,4,5]))
result = 200
function out=argEval(n,fh, varargin)
%Get the n-th output of fh(varargin{:})
[argsout{1:n}]=fh(varargin{:});
out=argsout{n};
end

jessupj
jessupj 2023년 12월 12일
what i've been doing lately, in case it's helpful to anyone, is to make a class containing my most commonly used functions that i need 2nd outputs from
e.g.
classdef arg2
methods(Static)
function locb = ismember(varargin)
[~, locb] = ismember(varargin);
end
function imax = max(varargin)
[~,imax] = max(varargin);
end
end
end
etc. And then when i want the second arguments, i just call arg2.ismember or arg2.max. Easy, but it would be super nice if this kind of thing was built in.
Another place the second argument is really important is the output of ODE solvers. I often only need the second argument of e.g. [TOUT,YOUT] = ode45(ODEFUN,TSPAN,Y0) to pass into an error calculation/optimizer/etc.
For this, i find the easiest thing to do is grab the solution from the structure output using the dot:
ode45(ODEFUN,TSPAN,Y0).y % or .x (for time points)
  댓글 수: 2
Matt J
Matt J 2023년 12월 12일
편집: Matt J 2023년 12월 12일
i just call arg2.ismember or arg2.max. Easy
You could also import them where needed, and then invoke them without prefixes,
import arg2.*
B = ismember(1,[0,1,2,3,4,5])
B = 2
C=max([1,3,5,7,1])
C = 4
jessupj
jessupj 2023년 12월 12일
@Matt J you are truly more fearless than i am! i would almost surely run something forgetting that these commands replace the default function use.

댓글을 달려면 로그인하십시오.


James Tursa
James Tursa 2018년 2월 9일
편집: James Tursa 2018년 2월 9일
Unless the function has an input argument syntax that specifies only returning B, you can't do this. You can throw away that A immediately with this syntax however:
[~,B] = ismember(1,[0,1,2,3,4,5]);
That won't prevent the function from calculating that 1st result, it is just thrown away immediately upon return so that it doesn't clutter your workspace.
  댓글 수: 2
Walter Roberson
Walter Roberson 2018년 2월 9일
Right. Unfortunately there is no way in MATLAB to specify that you want to extract a particular output number of an expression and use that: you have to write the outputs to variables.
James Tursa
James Tursa 2018년 2월 9일
It would be nice to have an "argout_wanted" that can be queried from within the function to find out which outputs the caller actually wants returned.

댓글을 달려면 로그인하십시오.


Grigory Tagiltsev
Grigory Tagiltsev 2018년 2월 9일
You have to call the function anyway. You can do [~,B] = ismember(1,[0,1,2,3,4,5]); and avoid A. It doesn't decrease a number of lines though. You can also cheat a bit and do [B,B] = ismember(1,[0,1,2,3,4,5]); in this case only the second output will be written to B.

Han Zerui
Han Zerui 2021년 2월 24일
편집: Han Zerui 2021년 2월 24일
Define your own ismember function:
data = rand(1,10);
result = data(myismember(1,[0,1,2,3,4,5]));
function Locb = myismember(varargin)
[~, Locb] = ismember(varargin);
end

카테고리

Help CenterFile Exchange에서 Characters and Strings에 대해 자세히 알아보기

태그

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by