在 MATLAB 中正确使用或避免使用 eval

Right use of eval or avoid it in MATLAB

在我的代码中,我使用特定的方式来定义测试函数:在一个单元格中,存储布尔类型的测试('<='、'>='、'=='...)。之后我想对特定值进行测试。我存储测试类型的原因是我的代码特定的,并且允许我在不事先了解测试类型的情况下编写代码。另一种方法是在每个布尔测试上指定测试,例如使用 switch 但我想避免它的那一刻。

MWE

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

typeTest{1}='<=';
typeTest{2}='<';

%create function
funCheck=@(x,y)eval([num2str(x),y,'0']);

%works
funCheck(1,'<')

%apply on cell (does not work due to the array in a)
cellfun(funCheck,a,typeTest)

使用此语法无法同时使用 eval 和矢量表达式...

如今在 MATLAB 中避免使用 eval 实际上非常容易。如果您将 typeTest 定义为一组函数句柄而不是字符串,那么您已经完成了 99%:

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

typeTest{1}=@le; % <=
typeTest{2}=@lt; % <

%create function
funCheck=@(x,y)y(x,0);

%works
funCheck(1,typeTest{1})

%apply on cell
cellfun(funCheck,a,typeTest,'UniformOutput',false)

请注意,我在 cellfun 的参数中添加了 'UniformOutput',false。这将创建一个元胞数组作为输出,其中每个元胞是 a 中的一个元素和 typeTest 中对应元素的剩余结果。也就是说,a{1} 用 TypeTest{1} 检查,a{2}TypeTest{2} 检查。

我实际上会创建一个包含所有实际测试的数组,如下所示:

checks = { @(x)x<=3 , @(x)x>4 };

现在您对运算符和正确的操作数进行编码。这使您可以灵活地创建其他类型的支票:@(x)var(x)<1e-3@(x)max(diff(x))<1

要将这些检查中的每一项应用于每个数据数组,您需要使用 bsxfun。我尝试了以下语句,但它在 Octave 3.0.0 中无法正常工作(我认为这可能是一个错误):

bsxfun( @(fun,data){fun{1}(data{1})}, checks(:)', a(:) )

这会生成一个包含结果的 2x2(检查次数乘以数据数组的数量)元胞数组。

上面的一个丑陋的替代方案是:

cellfun( @(fun,data)fun(data), ...
         repmat(checks(:)',numel(a),1), ...
         repmat(a(:),1,numel(checks)), ...
         'UniformOutput',false)