以编程方式获取有效的开关/案例值

时间:2013-06-26 16:30:27

标签: matlab

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

我意识到我可以强制它,只需将所有有效案例重新键入otherwise下的单元格数组,并让函数抛出错误并返回有效响应列表,但保留两个列表随着时间的推移,没有错误或懒惰是一个挑战。

3 个答案:

答案 0 :(得分: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数据结构来存储这种数据,例如:地图或单元格数组。有关详细信息,请参阅此问题的答案:MATLAB Changing the name of a matrix with each iteration

答案 1 :(得分: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;之前添加switch来重置持久变量并将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

风险解决方案:此解决方案可能违反了相当多的编程习惯,但仍然可以作为黑客攻击。假设你有嵌套的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

答案 2 :(得分: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 - 语句中的一个“匿名”列表,以及cases单元格数组中的一个。但每个“案例”仍然是一个单独的实体,案例条件按案例分组。

当然,你会失去switch的力量。

......还有更多的计划。所有可比较的,都具有相似的缺点。

我担心最好的方法就是与它一起生活并管理两个相同的列表。