2

I found an example in MATLAB 2007 in which cellfun and arrayfun can nearly be used interchangeably:

>> cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0)
% ans = 
%    'one'    'two'    'three'
>> arrayfun(@(c) c, {'one' 'two' 'three'})
% ans = 
%    'one'    'two'    'three'

I can also think of an example where arrayfun works but cellfun does not:

>> arrayfun(@(c) c, [1 2 3])
% ans =
%      1     2     3
>> cellfun(@(c) c, [1 2 3])
% ??? Error using ==> cellfun
% Input #2 expected to be a cell array, was double instead.

My question is this: are there any situations in which cellfun works but arrayfun does not? If yes, please give examples. If no, why does cellfun even need to exist?

Chad
  • 1,434
  • 1
  • 15
  • 30

3 Answers3

9

This is interesting. Your examples are performing two different operations, which happen to lead to the same result. It's kind of fun to explore.

TL;DR. You should generally use arrayfun when your input is an array, and cellfun when your input is a cell, although you can often force arrayfun to do the job, with varyig levels of syntax hell.

Fundamentally, arrayfun is meant to operate on arrays and cellfun is meant to operate on cells. But, the Matlab-wise will note that a cell is nothing more than an array of "cells", so arrayfun works anyway.


As you point out, the following two lines perform the same operation:

cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0)   %returns  {'one' 'two' 'three'}
arrayfun(@(c) c(1), {'one' 'two' 'three'});                  %returns  {'one' 'two' 'three'}

However, if we want to do something during our manipulations, it's a little different. For example, we may want to extract the first character of each string. Compare the results of cellfun and arrayfun here:

cellfun( @(c) c(1), {'one' 'two' 'three'}, 'uniformoutput', 0);  %returns {'o' 't' 't'}
arrayfun(@(c) c(1), {'one' 'two' 'three'});                      %Returns {'one' 'two' 'three'}

Do get the same result with arrayfun, we need to dereference the cell within the anonymous function, and then extract the character, and then put the results into a cell array rather than a character array. Like this:

arrayfun(@(c) c{1}(1), {'one' 'two' 'three'},'uniformoutput',false)  %Returns {'o' 't' 't'}

So the difference is that 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 {}), whereas arrayfun just performs the standard indexing (that is, the ()). In addition, the 'uniformoutput',false notation determines if the output is written to a regular arral or a cell array.

To show what this means in code, see the following functions which are equivalent to cellfun and arrayfun, both with and without the 'uniformoutput',false notation. These four functions are equivalent except for the use of the () vs. {} within the loop:

function out = cellFunEquivalent(fn, x)
    for ix = numel(x):-1:1
        out(ix) = fn(x{ix});
    end
    out = reshape(out,size(x));
end

function out = arrayFunEquivalent(fn, x)
    for ix = numel(x):-1:1
        out(ix) = fn(x(ix));
    end
    out = reshape(out,size(x));
end

function out = cellFunEquivalent_nonuniform(fn, x)
    for ix = numel(x):-1:1
        out{ix} = fn(x{ix});
    end
    out = reshape(out,size(x));
end

function out = arrayFunEquivalent_nonuniform(fn, x)
    for ix = numel(x):-1:1
        out{ix} = fn(x(ix));
    end
    out = reshape(out,size(x));
end

For the example you posted, the arrayfun function is actually operating on single element cells, and reconstructing a copy of those cells into another array of the same (cell) class (see arrayFunEquivalent). The cellfun operation is dereferencing each element of the input cell array and then reconstructing a copy of those strings into a cell array (see cellFunEquivalent_nonuniform). When the input x is a cell, these operations are equivalent.

Pursuit
  • 12,285
  • 1
  • 25
  • 41
  • 1
    *"arrayfun just performs the standard indexing (that is, the `()`)"* is an incorrect statement. I think your explanation is confusing. – Oleg Aug 14 '13 at 19:53
  • It was confusing, but I think the intent of the statement was correct. I've added sample functions demonstrating the intent of the statement. – Pursuit Aug 15 '13 at 18:32
  • *"Your examples are performing two different operations, which happen to lead to the same result."* Technically they perform the same `@(c) c` operation, the assignment is internally handled differently. *"You should generally use arrayfun when your input is an array, and cellfun when your input is a cell, although you can often force arrayfun to do the job, with varyig levels of syntax hell."* Statement not supported by examples/facts. Loose terminology which creates confusion. What is not an array? (alos, no need to force or hell for something that is clearly described in the docs) – Oleg Aug 15 '13 at 20:50
  • *"But, the Matlab-wise will note that a cell is nothing more than an array of "cells", so arrayfun works anyway."* This completes it all. Again, documentation is straightforward. In the examples you contradict yourself and skew the code of the OP showing that syntax is not completely clear to yourself. I understand that you put effort in your post, and I respect it. However, I felt that in this case it was important to avoid creating confusion. – Oleg Aug 15 '13 at 20:51
  • @Pursuit I just bumped into one example of this difference between `arrayfun` and `cellfun` and (remembering this question) was going to post it, but you've already done it very well here! Your explanation is very good. This should be the accepted answer. – Luis Mendo Sep 26 '13 at 10:51
4

There are a few built-in functions that can be referenced by name in cellfun but cannot be used in the same way in arrayfun. From the help:

A = CELLFUN('fun', C), where 'fun' is one of the following strings,
returns a logical or double array A the elements of which are computed
from those of C as follows:

   'isreal'     -- true for cells containing a real array, false
                   otherwise
   'isempty'    -- true for cells containing an empty array, false
                   otherwise
   'islogical'  -- true for cells containing a logical array, false
                   otherwise
   'length'     -- the length of the contents of each cell
   'ndims'      -- the number of dimensions of the contents of each cell
   'prodofsize' -- the number of elements of the contents of each cell

So cellfun('isreal', {'one' 'two' 'three'}) is a valid expression, but any similar call with arrayfun will trigger the First input must be a function handle error.

Of course, you can just use @isreal or @isempty for arrayfun

As for why cellfun still exists, I suspect it's historical (don't break backward compatibility)

SheetJS
  • 22,470
  • 12
  • 65
  • 75
0

cellfun() exists mainly for historical reasons, i.e. at least since 1998, while arrayfun() and structfun were introduced only in late 2005, in the R14SP3 release.

Also, as pointed out by Nirk in his answer, cellfun() supports some legacy syntax, limited to a few cases though, that is usually faster than the handle @ counterparty.

Reading from both documentations:

[B1,...,Bm] = arrayfun(func,A1,...,An)...passes elements from arrays A1,...,An, where n is the number of inputs, to the function func. ...The ith iteration corresponds to the syntax [B1(i),...,Bm(i)] = func(A1{i},...,An{i})...

[A1,...,Am] = cellfun(func,C1,...,Cn) calls the function specified by function handle func and passes elements from cell arrays C1,...,Cn...

So, the former accepts arrays, while the latter only cell arrays.

Abusing notation, in your first example you have A1 = C1 = {'one' 'two' 'three'} which is legit according to the docs, while in your second case A1 = [1 2 3] but C1 cannot be a numeric array.

Community
  • 1
  • 1
Oleg
  • 10,406
  • 3
  • 29
  • 57