在MATLAB中,cellfun是否总是可以用arrayfun替换?

Cha*_*had 2 arrays matlab

我发现了一个例子,2007年MATLAB中,cellfunarrayfun几乎可以互换使用:

>> cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0)
% ans = 
%    'one'    'two'    'three'
>> arrayfun(@(c) c, {'one' 'two' 'three'})
% ans = 
%    'one'    'two'    'three'
Run Code Online (Sandbox Code Playgroud)

我也可以想到一个有效的例子,arrayfuncellfun不是:

>> 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.
Run Code Online (Sandbox Code Playgroud)

我的问题是:有没有可行的情况cellfun但却arrayfun没有?如果是,请举例.如果不是,为什么cellfun甚至需要存在?

Pur*_*uit 8

这是有趣的.您的示例正在执行两个不同的操作,这恰好会导致相同的结果.这是一种探索的乐趣.

TL; DR.您通常应该arrayfun在输入是一个数组时使用,并且cellfun当您的输入是一个单元格时,尽管您经常可以强制arrayfun执行该任务,但语法地狱会有所不同.

从根本上说,arrayfun它意味着在阵列上运行,并且cellfun意味着在单元上运行.但是,Matlab明智地会注意到一个单元格只不过是一组"单元格",所以arrayfun无论如何都是有效的.


正如您所指出的,以下两行执行相同的操作:

cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0)   %returns  {'one' 'two' 'three'}
arrayfun(@(c) c(1), {'one' 'two' 'three'});                  %returns  {'one' 'two' 'three'}
Run Code Online (Sandbox Code Playgroud)

但是,如果我们想在操作过程中做些什么,那就有点不同了.例如,我们可能想要提取每个字符串的第一个字符.比较结果cellfunarrayfun这里:

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

使用arrayfun得到相同的结果,我们需要取消引用匿名函数中的单元格,然后提取字符,然后将结果放入单元格数组而不是字符数组.像这样:

arrayfun(@(c) c{1}(1), {'one' 'two' 'three'},'uniformoutput',false)  %Returns {'o' 't' 't'}
Run Code Online (Sandbox Code Playgroud)

所以区别在于,cellfun在循环(即,{})时,arrayfun负责对单元的各个元素进行详细操作所需的取消引用操作,而只执行标准索引(即,()).此外,'uniformoutput',false符号确定输出是写入常规arral还是单元数组.

要在代码中显示这意味着什么,请参阅以下函数,这些函数等效于cellfunarrayfun,有和没有'uniformoutput',false符号.这四个函数是等效的,除了在循环中使用()vs {}:

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
Run Code Online (Sandbox Code Playgroud)

对于您发布的示例,该arrayfun函数实际上在单个元素单元格上运行,并将这些单元格的副本重建为同一(单元格)类的另一个数组(请参阅参考资料arrayFunEquivalent).该cellfun操作将取消引用输入单元阵列的每个元素,然后将这些字符串的副本重建为单元数组(请参阅参考资料cellFunEquivalent_nonuniform).当输入x是单元格时,这些操作是等效的.