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?

Acorbe
  • 8,367
  • 5
  • 37
  • 66

2 Answers2

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
angainor
  • 11,760
  • 2
  • 36
  • 56
  • 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? – Acorbe Nov 21 '12 at 10:52
  • @Acorbe 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. – angainor Nov 21 '12 at 11:07
  • 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. – Acorbe Nov 21 '12 at 11:13
  • Speaking more abstractly what I need looks more like `f = @(c)foo(x)[2]` – Acorbe Nov 21 '12 at 11:16
  • 1
    @Acorbe I understand, but as far as I know, you can not do that. Also, have a look at [this SO post](http://stackoverflow.com/questions/3096281/skipping-outputs-with-anonymous-function-in-matlab). The bottom line - you will have to define wrappers. – angainor Nov 21 '12 at 11:28
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}