Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is wrapping the function with the {} operator a valid replacement of 'UniformOutput', false in cellfun?

I am using cellfun to apply a function to each cell in a cell array.

I know that I must set 'UniformOutput' to false whenever the function returns non-scalar values, so that the outputs of the function are returned encapsulated in a cell array.

Take the following cell array as an example:

C1 = {[1 2 3], [4 5 6]};

C1 has two cells and each cell contains a vector of three elements:

C1 =

  1×2 cell array

    [1×3 double]    [1×3 double]

If I want to add 1 to the contents in every cell, I can define the function @(x) x + 1 and apply it using cellfun as follows:

C2 = cellfun(@(x) x + 1, C1, 'UniformOutput', false);

This works very well, but note that I need to make sure that 'UniformOutput' is set to false as I explained before, otherwise an error would be thrown.

However, after reading this thread, I realized that if I wrap the function with the cell array construction operator {} like this @(x) {x + 1} then I don't need to set 'UniformOutput' to false.

So the following command will generate the same results as in C2 without throwing any errors:

C3 = cellfun(@(x) {x + 1}, C1);

In terms of code layout I prefer this approach since it is more compact and less verbose than the former, but I am not sure if this is always safe.


Thus my question is:

Can I always wrap the function with {} to avoid setting 'UniformOutput' to false? Or are there any scenarios where such replacement would not work?


My research:

help cellfun

'UniformOutput' -- a logical value indicating whether or not the output(s) of FUN can be returned without encapsulation in a cell array. If true (the default), FUN must return scalar values that can be concatenated into an array. If true, the outputs must be of the following types: numeric, logical, char, struct, cell. If false, cellfun returns a cell array (or multiple cell arrays), where the (I,J,...)th cell contains the value FUN(C{I,J,...}, ...). When 'UniformOutput' is false, the outputs can be of any type.

The following fragment is part of an answer to a related question:

[...] cellfun takes care of the dereference operation which is required to do detailed operations on individual elements of a cell when looping (that is, the {}) [...]

like image 367
codeaviator Avatar asked May 21 '17 23:05

codeaviator


People also ask

What does Cellfun mean in Matlab?

A = cellfun( func , C ) applies the function func to the contents of each cell of cell array C , one cell at a time. cellfun then concatenates the outputs from func into the output array A , so that for the i th element of C , A(i) = func(C{i}) .

What is Matlab UniformOutput?

Direct link to this answer Option Uniform or UniformOutput set to 0 (or false) means, that output from function will be stored in cell array. It is necessary when function (in your case plus) returns non scalar values.


1 Answers

There are two scenarios I can think of where using cell encapsulation instead of the additional arguments ...'UniformOutput', false) would cause a problem, the first one being a much more likely scenario than the second:

  • Capturing multiple outputs: Sometimes you may want to capture multiple outputs from the function you are applying, such as calling unique on each element of your cell array and getting the additional index arguments. Using ...'UniformOutput', false) we can easily do this:

    >> C1 = {[1 2 3], [4 5 6]};
    >> [C2, index] = cellfun(@(x) unique(x), C1, 'UniformOutput', false)
    C2 =
      1×2 cell array
        [1×3 double]    [1×3 double]
    index =
      1×2 cell array
        [3×1 double]    [3×1 double]
    

    However, this fails when using cell encapsulation:

    >> [C2, index] = cellfun(@(x) {unique(x)}, C1)
    Output argument "varargout{2}" (and maybe others) not assigned during call to
    "@(x){unique(x)}".
    
  • Functions with no output: I know what you're thinking: "But if they produce no output, then I don't have to worry about collecting non-scalar values!" True, but I'm imagining an admittedly unusual scenario where the function to be evaluated may be an additional parameter, like a function handle passed as an argument, so you don't know a priori how many outputs you'll be dealing with. Regardless, the two approaches differ for such a case:

    >> C1 = {[1 2 3], [4 5 6]};
    >> cellfun(@(x) disp(x), C1, 'UniformOutput', false);
         1     2     3
         4     5     6
    
    >> cellfun(@(x) {disp(x)}, C1);
    Error using disp
    Too many output arguments.
    Error in @(x){disp(x)}
    

    Probably not something you'll ever have to worry about, but I thought I'd include it for the sake of completeness.

like image 175
gnovice Avatar answered Oct 23 '22 06:10

gnovice