如何在匿名函数中使用条件语句

7

一个函数可以定义为@(x) x^.2(例如)。

但是,如果我们有一个函数在不同的区间上采用不同的表达式,例如:if abs(x)<3 fun = x^.2 else 0

我们如何使用相同的方法(即使用@(x))来定义这样一个函数。


1
可能是如何在MATLAB匿名函数中执行多个语句?的重复问题。 - Shai
2
@Shai:不同意。那个问题是关于在单个匿名函数中进行多个函数评估,而这个问题是关于在匿名函数中进行条件评估(有一个重复的问题,我已经看到了,但现在找不到它...) - Rody Oldenhuis
4个回答

18

有几种方法可以做到这一点。

乘以 false:

g = @(x) (abs(x)<3) .* x.^2

或者定义一个适当的函数(确实是最好的方法):

function y = g(x)

    y = zeros(size(x), class(x));

    inds = abs(x)<3;
    y(inds) = x(inds).^2;

end 

或者做那些凌乱丑陋低效但有趣的事情,使用内联if语句

iif = @(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
g = @(x) iff( ...
    abs(x)<3,  x.^2, ...
        true,  0);

2
更多解释:当您想要避免计算未被选择的其他部分时,甚至需要一个适当的函数;例如:iif(x==0;0;1/x),即使 x==01/x 仍然会被评估。这是一个函数,Matlab 仍然希望传递所有参数,因此进行了评估。避免这种情况的唯一方法(也是最好的、正确的方法)是使用一个单独的函数,它允许多行和正常的 if - Gunther Struyf
@GuntherStruyf:真的。将“inefficient”添加到iif()方法的描述中 :) - Rody Oldenhuis
@GuntherStruyf:啊呼。那是“低效”的。打字很难。 - Rody Oldenhuis
这段代码主要是为了避免错误而添加的注释。看起来像是if/then/else语句,但实际上在执行时并不是这样的。不过,确实效率比较低 ;) - Gunther Struyf

0
这是我想出来的。我有一个名为cases.m的函数,其定义如下:
function [ val ] = cases( table )
  [rows,~] = size(table);
  for i = drange(1:rows)
    condition = table{i,1};
    if (ischar(condition) && strcmpi(condition,'else')) || feval(condition)
      val = feval(table{rows,2});
      return
    end
  end
  val={};
end

cases 函数接受一个包含两列的单元数组。每个元素都是一个没有参数的函数。对于每一行,它会取第一个元素,如果它是字符串 'else' 或者是返回 true 值的函数,则调用第二个元素并返回其值。如果没有符合条件的行,则返回一个空单元格。这些元素是零元函数而不是值,以便不需要的情况不被评估。

然后我可以像这样编写 case 表达式:

w=arrayfun(@(j) cases({ ...
   @() (j==0 || j==n) @() (-1)^j/2; ...
   'else' @() (-1)^j }), 0:n);

这将生成一个数组,其中包含从0到n的值,并将第一个和最后一个值减半。


0

如@Gunther在上面的评论中提到的,可以创建一个通用函数来处理简单条件以模拟三元运算符?:,以绕过Matlab不允许在匿名函数内使用条件语句的限制(如果你不计算那个混乱丑陋低效但有趣的内联版本:)。

解决方案通过这个链接提供(可能还有其他一些地方,但在我的谷歌搜索中,SO排在第一位,所以觉得应该在这里添加)。 http://www.mathworks.co.jp/matlabcentral/newsreader/view_thread/158054

定义一个名为iffifelse的函数,并将其添加到Matlab路径中。

function result = ifelse(condition,trueResult,falseResult)
    error(nargchk(3,3,nargin));  % check correct number of input args
    if condition
        result = trueResult;
    else
        result = falseResult;
    end

然后像这样使用

predict = arrayfun(@(x) ifelse(x>=0.5,1,0), inputData);

在楼主的情况下,可以使用类似这样的代码。
arrayfun(@(x) ifelse(abs(x)<3,x^.2,0), data)

0

关于@RodyOldenhuis答案中提到的链接隐藏,可以看一下函数式编程构造。该软件包提供了一个相当全面的函数式构造集合。作者还在MATLAB博客的客座帖子中展示了这个库背后的许多细节。如果您不想将整个软件包拉入您的项目中,博客文章还包括软件包中某些函数的匿名单行代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接