5

当 MATLAB 扫描switch/case块中的案例时,它是否记得它跳过的值,是否可以访问该列表?我有一些带有长switch\case块的函数,如果它们降低到otherwise. 例如,我有一个函数可以返回一组材料的光学常数。它目前有大约 20 种不同的材料,并且随着我考虑新的材料而不断增长。

我意识到我可以暴力破解它,只需将所有有效案例重新输入到下面的单元格数组中,otherwise并让函数抛出错误并返回有效响应列表,但保持两个列表没有错误或随着时间的推移出现懒惰具有挑战性。

4

3 回答 3

6

为了澄清,听起来你要求做的事情如下:

value = 'z';
output = [];
switch value
    case 'a'
        output = 1.234;
    case 'b'
        output = 2.345;
    case 'c'
        output = 3.456;
    otherwise
        output = [];
        disp('Please use one the the following values:  a, b, c')
        %It would be nice to auto-populate that string wouldn't it?
end

这在 Matlab(或我知道的任何语言)中是不可能直接实现的。


但是,如果您从 switch/case 语句转移到更加以数据为中心的代码设计,它就会变得容易。例如,上面的代码可以重写为:

%Setup (this can be preloaded and stored as persistent if too time consuming)
count = 1;
allvalues(count).name = 'a'; allvalues(count).value = 1.234; count = count+1;
allvalues(count).name = 'b'; allvalues(count).value = 2.345; count = count+1;
allvalues(count).name = 'c'; allvalues(count).value = 3.456; count = count+1;

%Lookup
value = 'z';  %Also try value = 'a'

maskMatch = strcmp({allvalues.name},value);
if any(maskMatch)
    output = allvalues(maskMatch).value;
else
    disp('Please use one of the following values:');
    disp({allvalues.name});
end

这是使用结构数组存储数据的示例。有很多方法可以使用 Matlab 数据结构来存储这种数据,例如 Map 或单元数组。有关比较全面的列表,请参阅此问题的答案: MATLAB 每次迭代更改矩阵的名称

于 2013-06-26T16:44:12.310 回答
3

编辑:在收到关于我的第一个解决方案的迷人评论后,我提出了另一个解决方案,它需要在您的代码中进行比第一个解决方案更多的编辑,但到目前为止仍比其他解决方案少(将原始解决方案移到最后):

让我们定义一个函数来获取值并将它们保存在一个持久变量中

function list = cc(value)
persistent allCases
if isempty(allCases) || (nargin == 0 && nargout == 0)
    allCases = {};
end
if nargin == 1,
    allCases = [allCases value]; 
    list = value;
end
if nargin == 0 && nargout == 1,
    list = allCases;
end
end

现在您只需添加一个cc;beforeswitch来重置持久变量并将case语句中的所有值传递给函数并调用otherwise部分中的函数来读取值:

a = 'a';
v = 'c';

cc;
switch a
    case cc({'b' v 1.2})
        %Multiple cases 
    case cc(2)
        %number
    case cc(ones(2))
        %matrix
    otherwise
        disp('Allowed cases are:');
        cellfun(@disp, cc);
end

这打印出来:

Allowed cases are:
b
c
    1.2000
     2
     1     1
     1     1

有风险的解决方案:这个解决方案可能违反了很多编程实践,但仍然可以作为 hack。假设您没有嵌套switch语句,那么您可以在语句中调用这样的函数otherwise

function allCases = getCases
st = dbstack('-completenames');
line = st(2).line;
fLines = importdata(st(2).file, sprintf('\n'));
switchLine = find(~cellfun(@isempty, ...
    regexp(fLines(1:line-1), '^\s*switch\s', 'once')), 1, 'last');
otherwLine = find(~cellfun(@isempty, ...
    regexp(fLines(1:line-1), '^\s*otherwise\s*$', 'once')), 1, 'last');
caseLines = fLines(switchLine+1:otherwLine-1);
casesStr = regexprep(caseLines(~cellfun(@isempty, ...
    regexp(caseLines, '^\s*case\s', 'once'))), '^\s*case\s*', '');
casesCells = cell(size(casesStr));
for iCases = 1:numel(casesCells);
    casesCells{iCases} = evalin('caller', casesStr{iCases});
end
allCases = [casesCells{:}];
end

然后,如果您运行这样的代码

a = 'a';
v = 'c';

switch a
    case {'b' v 1.2}
        %Multiple cases 
    case 2
        %number
    case ones(2)
        %matrix
    otherwise
        disp('Allowed cases are:');
        cellfun(@disp, getCases);
end

它打印出来

Allowed cases are:
b
c
    1.2000
     2
     1     1
     1     1
于 2013-06-26T18:24:16.127 回答
2

AFAIK,没有这样的机制。在特定情况下可能会使用一些矢量化技巧,但一般来说,不会。

而且,如果仅从(内存)效率的角度来看,实现switch类似的东西也是一个坏主意(所有情况都可能是巨大的矩阵)。

您可以将这样的机制组合在一起:

% define all your cases in a cell
cases = {...
    'case1', 'case2', ...};

% and switch on these cases
switch [condition]
    case cases{1}
       % implement 'case1' 

   case cases{2}
       % implement 'case2' 

    ...

    otherwise
        char(cases) % contains all cases

end

显然,你获得的一般性,你会失去可读性;现在,各个案例与其对应的代码不在同一位置。另外,内容的顺序cases很重要,[继续列出许多缺点] ...

简而言之,它不是很漂亮。

您可以自己即时建立一个列表:

cases = {}; 

% FIRST CASE
if strcmp([condition], 'case1')
    % code for 'case1'

else % insert the case just checked for in the new list
    cases{end+1} = 'case1';
end

% SECOND CASE
if strcmp([condition], 'case2')
    % code for 'case2'

else % insert the case just checked for in the new list
    cases{end+1} = 'case2';
end

... % etc.

您实际上仍然在构建 2 个列表:一个在if-statements 中的“匿名”列表,一个在cases单元格数组中。但是每个“案例”仍然是一个单独的实体,案例条件是按案例分组的。

当然,你确实失去了 a 的力量switch

...还有更多的方案。都具有可比性,并且都具有可比的缺点。

恐怕去这里的最好方法就是忍受它并管理两个相同的列表。

于 2013-06-26T16:49:20.463 回答