使用cellfun检查工作区中的变量是否存在

9
考虑下面的例子:
dat1 = 1;
dat2 = 2;

Variables = {'dat1','dat2'};

a = cellfun(@(x)exist(x,'var'),Variables);

for i = 1:length(Variables);
    a2(i) = exist(Variables{i},'var');
end

为什么'a'和'a2'返回不同的值,即为什么使用cellfun不声明变量存在于工作区?我错过了什么?

哇,这真的很奇怪。我已经检查了那个带有 @ 的函数表达式:1. 可以访问环境中的变量 -and- 2. 保留了参数的正确类型。两者都是正确的,这真的很奇怪。在我看来,你刚刚发现了 cellfunexist 中的一个错误!恭喜 :) - plesiv
@Kate:你所忽略的是每个匿名函数都有自己的工作空间(我也花了一段时间才明白)。请看下面我的回答。 - Jonas
2个回答

4

好的,我理解这里正在发生什么:

当您调用匿名函数时,它会创建自己的工作区,就像任何普通函数一样。但是,这个新的工作区将无法访问调用者的工作区。

因此

funH = @(x)exist(x,'var')

如果你输入'x'funH('x')),那么它只会返回1,因为它的整个工作区仅包含变量'x'

因此,

funH = @(x)exist('x','var') 

无论您输入什么,都将始终返回1。

有两种可能的解决方法:

(1) 使用evalin在调用者的工作空间中进行评估

 funH =  @(x)evalin('caller',sprintf('exist(''%s'',''var'')',x))

(2) 使用 whos 命令的输出结果,并与已存在的变量列表进行对比。

 Variables = {'dat1','dat2'};
 allVariables = whos;
 a3 = ismember(Variables,{allVariables.name})

我有点困惑。如果新的工作区没有访问调用者的工作区,那么这段代码 b = 3; feval(@(x) b+x, 2) 怎么会返回 5 呢?你能解释一下吗? - plesiv
1
在将b添加到匿名函数的定义中时,您向匿名函数的工作区添加了一个副本。如果在定义匿名函数后更改b的值,则匿名函数内部的b不会更改。 - Jonas

2

我认为你应该将cellfun行写成:

a = cellfun(@(x) exist('x','var'),Variables); 

使其等价于 for 循环。 另请参阅如何在Matlab文档中使用exist的示例...

编辑:

在理解 Jonas 的答案后,上面的代码将始终返回 true,无论 dat1=1 还是 dat1=[]。为了使用 cellfun,请查看 Jonas 的回答...


我错了。你的函数将始终返回true,无论输入是什么。 - Jonas
从cellfun的示例中并没有显示x应该放在引号之间。Cpositives = cellfun(@(x) x(x>0), C, 'UniformOutput',false)因此我认为这不是正确的方法。 - Dennis Jaheruddin

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