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) ofFUN
can be returned without encapsulation in a cell array. Iftrue
(the default),FUN
must return scalar values that can be concatenated into an array. Iftrue
, the outputs must be of the following types: numeric, logical, char, struct, cell. Iffalse
,cellfun
returns a cell array (or multiple cell arrays), where the (I,J,...)th cell contains the value FUN(C{I,J,...}, ...). When'UniformOutput'
isfalse
, 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{}
) [...]
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}) .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With