Matlab: defining a function handle catching second returned value of a function
Asked Answered
F

2

11

Say that I have a function foo defined as

   [a b] = foo(c ).

If I consider a function handle

 f = @(c)foo(c)

to be used e.g. in a cellfun call, what I get is an f behaving equivalently to a foo defined like

  a = foo(c)

i.e., the returned value b gets lost.

Therefore, when such an f is put in a cellfun call, the output cell will have just the as and will miss the bs (which I currently care about). Visually

    cellfun(f,input)

  [a(input{1})]           ?
  [a(input{2})]           ?
     ....            b gets killed along the way

Question: how to define a function handle to foo which catches just the bs? i.e. giving a behavior analogous to a definition of foo like

  b = foo(c)

i.e.^2, wasting the as.

Moreover, is it possible to (efficiently) catch both a and b in a unique cellfun call?

Frager answered 21/11, 2012 at 9:27 Comment(0)
C
7

From the documentation of cellfun:

[A1,...,Am] = cellfun(func,C1,...,Cn) calls the function specified by function handle func and passes elements from cell arrays C1,...,Cn, where n is the number of inputs to function func. Output arrays A1,...,Am, where m is the number of outputs from function func, contain the combined outputs from the function calls.

So yes, cellfun can use a multi-output function and in this case it simply returns a number of outputs. If you want to use the second one only, you can use ~ to ignore the first one. The same goes for multiple outputs of anonymous functions - they will be returned if you specify multiple output arguments. Here is a simple code:

function test
    x{1} = 1;
    x{2} = 2;
    [~, B] = cellfun(@foo, x);
    f=@(c)foo(c);
    [A, B] = f(1);

    function [a b] = foo(x)
        a = x+1;
        b = x+2;
    end
end
Checkerbloom answered 21/11, 2012 at 10:45 Comment(5)
Nice, it worked for what concerns the cellfun call; in my case I put [A,B] and not [~,B], my matlab version doesn't support it. So the second point is successfully answered! As far as I can see the general problem of getting the second returned argument in a lambda definition still holds. Isn't it?Frager
@Frager See the updated answer. It is exactly the same - you can not change the declaration of a function, but you can specify multiple outputs to your anonymous function call.Checkerbloom
Well that I see.. I am still looking for something that doesn't need to do the [A , B] = foo stuff. Mainly for retrocompatibility issues. Indeed one can wrap the function foo in another function (non function handle), loosing the lambda flavor though. Thank you for highlighting that part of the manual which I read not carefully enough.Frager
Speaking more abstractly what I need looks more like f = @(c)foo(x)[2]Frager
@Frager I understand, but as far as I know, you can not do that. Also, have a look at this SO post. The bottom line - you will have to define wrappers.Checkerbloom
T
2

This can be done by using a cell array as the single output of the function, instead of a function with multiple outputs.

Define your function to return a cell array (or create an auxiliary function that calls the original multiple-output function):

function F = foo2(x)
  [a,b,c] = foo(x);
  F = {a, b, c};
end

And then you can create a handle that calls your function and gets only one of the cells from the cell array.

f = @(x) cell(foo2(x)){2} % This selects the second output
g = @(x) cell(foo2(x)){3} % This selects the third output

Which is almost exactly what you were asking for. You could even create a handle that returns the n-th output

f = @(x,n) cell(foo2(x)){n}
Teriteria answered 15/9, 2015 at 16:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.