将函数与{}运算符包装在一起有效替换' UniformOutput',在cellfun中为false?

时间:2017-05-21 23:24:26

标签: matlab function cell-array

我正在使用cellfun将函数应用于单元格数组中的每个单元格。

我知道每当函数返回非标量值时,我必须将'UniformOutput'设置为false,以便将函数的输出封装在单元格数组中。

以下列单元格数组为例:

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

C1有两个单元格,每个单元格包含三个元素的向量:

C1 =

  1×2 cell array

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

如果我想将1添加到每个单元格的内容中,我可以定义函数@(x) x + 1并使用cellfun应用它,如下所示:

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

这非常有效,但请注意,我需要确保'UniformOutput'设置为false,如前所述,否则会引发错误。

然而,在阅读this thread后,我意识到如果我使用@(x) {x + 1}这样的'UniformOutput'包裹函数,那么我就不需要设置falseC2

因此,以下命令将生成与C3 = cellfun(@(x) {x + 1}, C1); 中相同的结果,而不会抛出任何错误:

{}

在代码布局方面,我更喜欢这种方法,因为它比前者更紧凑,更简洁,但我不确定这是否总是安全的。

因此我的问题是:

我是否可以始终使用'UniformOutput'包裹该功能,以避免将false设置为help cellfun ?或者有任何情况下这种替换不起作用吗?

我的研究:

'UniformOutput'
  

FUN - 表示是否为的逻辑值   true的输出可以在没有封装的情况下返回   阵列。如果FUN(默认值),则true必须返回标量值   可以连接成一个数组。如果false,则输出必须为   以下类型:数字,逻辑,字符,结构,单元格。如果   cellfun'UniformOutput'返回一个单元格数组(或多个单元格数组),   其中(I,J,...)单元格包含值FUN(C {I,J,...},...)。   当falsecellfun时,输出可以是任何类型。

以下片段是相关问题cell array construction operator {}的一部分:

  

[...] {}负责解除引用操作   要求对单元格的各个元素进行详细操作   循环时(即{{1}})[...]

2 个答案:

答案 0 :(得分:15)

有两种情况我可以想到使用cell encapsulation代替附加参数...'UniformOutput', false)会导致问题,第一种情况比第二种更可能出现:

  • 捕获多个输出:有时您可能希望从正在应用的函数中捕获多个输出,例如在单元阵列的每个元素上调用unique并获取其他索引参数。使用...'UniformOutput', false)我们可以轻松完成此操作:

    >> 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]
    

    但是,使用单元格封装时会失败:

    >> [C2, index] = cellfun(@(x) {unique(x)}, C1)
    Output argument "varargout{2}" (and maybe others) not assigned during call to
    "@(x){unique(x)}".
    
  • 没有输出的功能:我知道你在想什么:"但如果他们没有输出,那么我就没有担心收集非标量值!" 是的,但我想象一个公认的不寻常场景,其中要评估的函数可能是一个附加参数,比如作为参数传递的函数句柄,所以你不知道先验你将要处理多少输出。无论如何,这两种方法在这种情况下有所不同:

    >> 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)}
    

    可能不是你不必担心的事情,但我认为为了完整起见我会把它包括在内。

答案 1 :(得分:2)

从你的问题......

  

我是否可以始终用{}包裹该功能,以避免设置“UniformOutput'是假的?或者有任何情况下这种替换不起作用吗?

简短的回答是" NO" 。我相信你的匿名函数失败的主要原因是它缺乏类型检查,程序员对函数返回类型知之甚少。

事实上,IMO你不应该使用单元索引操作符{}在你的匿名函数中包装你的返回值。更好的做法是在调用cellfun之后确定返回值类型,或在调用cellfun之前检查输入值类型。当然,您也可以在function handle中实施类型检查程序或try...catch,以确保完全控制您的退货类型。说实话,知道你发送的内容以及你将要收到的内容在Matlab中非常重要。

简而言之,您不应该使用{}来封装您的匿名函数,除非您有意创建一个单元格数组作为返回类型,并且您已知道该函数的返回值你被调用可以用来创建一个单元格数组。

仅供参考,如果您有2016b或更高版本,而function in script is possible,则可以在脚本中为cellfun创建函数句柄,而无需创建新文件。