MATLAB中循环的动态变化
设置循环时,我希望能够循环未知数量的参数 通过一个输入文件,用户可以设置任意多或任意少的循环参数,我希望无论设置了多少个参数,都可以在这些参数上循环。循环输入示例:(注意,我的输入也可以是字符串和数字组合的列表) 案例1:MATLAB中循环的动态变化,matlab,for-loop,dynamic,Matlab,For Loop,Dynamic,设置循环时,我希望能够循环未知数量的参数 通过一个输入文件,用户可以设置任意多或任意少的循环参数,我希望无论设置了多少个参数,都可以在这些参数上循环。循环输入示例:(注意,我的输入也可以是字符串和数字组合的列表) 案例1: 重量45000:5000:75000 海拔10000 速度0.2:0.1:0.9 案例2: 重量30000 海拔1000:1000:10000 襟翼10、20 温度-10:1:10 列表的长度可以不同,可以包含0-15个变量。我知道解决方法,但使用一堆嵌套for循环来
- 重量45000:5000:75000
- 海拔10000
- 速度0.2:0.1:0.9
- 重量30000
- 海拔1000:1000:10000
- 襟翼10、20
- 温度-10:1:10
parms.weight = [45000:5000:75000];
parms.alt = 10000;
parms.Speed = 0.2:0.1:0.9;
然后,定义您的模拟器,如下所示:
function result = simulation(parms)
fieldNames = fieldnames(parms)
result = [];
for ix = 1 : numel(fieldNames)
if 1 < numel(parms.(fieldNames{ix}))
list = parms.(fieldNames{ix});
for jx = 1 : numel(list)
tmpParms = parms;
tmpParms.(fieldNames{ix}) = list(jx);
tmpResult = simulation(tmpParms);
result = [result; tmpResult];
end
return;
end
end
if 0 == numel(result)
% Do the real simulation here.
end
函数结果=模拟(parms)
字段名=字段名(parms)
结果=[];
对于ix=1:numel(字段名)
如果1
为所有参数执行嵌套的-循环是一个简单的解决方案,常量参数只会导致该特定循环的一次迭代
您还可以使用创建一组多维数组,这些数组是computeFunction(…)
每次调用的参数,如果您希望更改参数的数量,则可以迭代ngrid的
输出,而不是为每个可能可变的参数构建嵌套for循环
但是,请注意,它可能会以性能为代价,因为这取决于您在哪个matlab版本中具体执行的操作,它可能不会从“简单”for loop版本的内置优化中获益。这里有一个递归函数,它生成所有可能的参数集作为数组的列向量:
function idx=dynloop(varargin)
if nargin==1
idx=varargin{1};
else
idx=dynloop(varargin{2:end});
idx=[repelem(varargin{1},size(idx,2));
repmat(idx,[1,length(varargin{1})])];
end
return
示例输出:循环5:7
,然后8
,然后[2,3,5,7]
:
>> idx = dynloop(5:7,8,[2,3,5,7])
idx =
5 5 5 5 6 6 6 6 7 7 7 7
8 8 8 8 8 8 8 8 8 8 8 8
2 3 5 7 2 3 5 7 2 3 5 7
输出相当于ndgrid
,(我认为形状更直观的情况除外)。(此外,一些初步基准测试表明,这可能略快于ndgrid
。?,有待确定)
主循环:现在只需使用一个循环来遍历idx
的列。注:该解决方案概念与@Daniel在OP上的评论类似
Weight = 45000:5000:75000;
Altitude = 10000;
Speed = 0.2:0.1:0.9;
idx = dynloop(Weight,Altitude,Speed);
for ii=1:size(idx,2)
params = idx(:,ii);
%// do stuff with params!
%// ...
end
编辑:处理字符串和数字输入
我发布的原始递归函数的一个简单修改允许它返回索引,而不是实际元素,因此字符串单元格很好:
function idx=dynloop(varargin)
if nargin==1
idx=1:length(varargin{1});
else
idx=dynloop(varargin{2:end});
idx=[repelem(1:length(varargin{1}),size(idx,2));
repmat(idx,[1,length(varargin{1})]);];
end
return
总之,你的函数大概是这样运行的:
function yourMainFcn(varargin)
idx=dynloop(varargin{:});
for ii=1:size(idx,2)
params = cellfun(@(x,k) numORcell(x,k),...
varargin,num2cell(idx(:,ii).'),... %//'
'UniformOutput',0);
%// do stuff with params!
%// ...
disp(params)
end
end
其中函数numORcell
正确解析数值与单元格数据:
function y=numORcell(x,k)
if iscell(x)
y=x{k};
else
y=x(k);
end
end
字符串示例:
Weight = 45000:5000:75000;
Altitude = 10000;
Speed = 0.2:0.1:0.9;
Names = {'Foo','Bar'};
>> yourMainFcn(Names,Altitude,Weight)
'Foo' [10000] [45000]
'Foo' [10000] [50000]
'Foo' [10000] [55000]
'Foo' [10000] [60000]
'Foo' [10000] [65000]
'Foo' [10000] [70000]
'Foo' [10000] [75000]
'Bar' [10000] [45000]
'Bar' [10000] [50000]
'Bar' [10000] [55000]
'Bar' [10000] [60000]
'Bar' [10000] [65000]
'Bar' [10000] [70000]
'Bar' [10000] [75000]
或者:
>> yourMainFcn(Names,Names,Speed,Names)
'Foo' 'Foo' [0.2] 'Foo'
'Foo' 'Foo' [0.2] 'Bar'
'Foo' 'Foo' [0.3] 'Foo'
'Foo' 'Foo' [0.3] 'Bar'
'Foo' 'Foo' [0.4] 'Foo'
...
'Foo' 'Foo' [0.9] 'Bar'
'Foo' 'Bar' [0.2] 'Foo'
...
'Foo' 'Bar' [0.9] 'Bar'
'Bar' 'Foo' [0.2] 'Foo'
...
'Bar' 'Foo' [0.9] 'Bar'
...
'Bar' 'Bar' [0.8] 'Foo'
'Bar' 'Bar' [0.8] 'Bar'
'Bar' 'Bar' [0.9] 'Foo'
'Bar' 'Bar' [0.9] 'Bar'
留给读者的练习:如果将所有索引存储在
idx
中是一个内存问题,那么您一定是在做一些相当繁重的循环。尽管如此,您可以创建一个函数,从当前索引集确定下一个词典索引集,这意味着您只需存储一组索引,并在每个循环结束时迭代 代码生成解决方案
你已经有很多很好的解决方案了。我将在这里抛出一个涉及代码生成的代码。MATLAB在这类工具方面并没有太多的功能,但您可以通过几个循环和fprintf
来伪造它。以下是我的代码生成脚本:
s = struct() ;
s.weight = 45000:5000:75000 ;
s.altitude = 10000 ;
s.engine = {'ge','rolsroyce'} ;
h = fopen('thisrun.m','w+') ;
mydisp = @(varargin)disp(transpose(varargin(:))) ; % dummy function body
vars = fields(s) ;
nv = numel(vars) ;
for ii = 1:nv
if isnumeric(s.(vars{ii}))
lb = '(' ;
rb = ')' ;
else
lb = '{' ;
rb = '}' ;
end
fprintf(h,'for i%g = 1:numel(s.(vars{%g})) \n',ii,ii) ;
fprintf(h,'i%gval = s.(vars{%g})%si%g%s ; \n',ii,ii,lb,ii,rb) ;
end
fprintf(h,'mydisp(') ;
for ii = 1:numel(vars)
fprintf(h,'i%gval',ii) ;
if ii<nv
fprintf(h,',') ;
end
end
fprintf(h,') ; \n') ;
for ii = 1:nv
fprintf(h,'end \n') ;
end
fclose(h) ;
run thisrun.m
运行生成代码的结果:
>>
[45000] [10000] 'ge'
[45000] [10000] 'rolsroyce'
[50000] [10000] 'ge'
[50000] [10000] 'rolsroyce'
[55000] [10000] 'ge'
[55000] [10000] 'rolsroyce'
[60000] [10000] 'ge'
[60000] [10000] 'rolsroyce'
[65000] [10000] 'ge'
[65000] [10000] 'rolsroyce'
[70000] [10000] 'ge'
[70000] [10000] 'rolsroyce'
[75000] [10000] 'ge'
[75000] [10000] 'rolsroyce'
代码生成需要时间,但如果需要多次运行该文件,它可能仍然是一个有效的解决方案 你在找吗?我会解析输入文件并将结果作为参数传递给函数。不需要进行任何解析。只需编写代码以使用最大循环数(例如,循环过载、高度、速度、温度、襟翼等)。在其中一个参数为常量的情况下,它实际上不会循环,只需设置一次索引并移动到下一个循环。@transversality condition我适当地解析数据,并将其作为结构发送到循环中。我当前的设置基本上就是您所描述的,但我正在寻找更优雅、更灵活的设置-如果添加了一个我没有预见到的新变量,该怎么办?我希望代码能够无缝地处理这个问题。@excaza我完全按照你说的做,但这是解析阶段。我希望能够在将任意数量的输入发送到函数进行计算之前对其进行适当的解析。我经常遇到这个问题,但出于某种原因,您的问题促使我以一种全新的方式思考这个问题。很好的问题。你的代码有问题,我得到了很多组合。只要尝试一下struct('a',[12],'b',[3],'c',[4,5],'e',[6,7])。我希望有6个电话
>>
[45000] [10000] 'ge'
[45000] [10000] 'rolsroyce'
[50000] [10000] 'ge'
[50000] [10000] 'rolsroyce'
[55000] [10000] 'ge'
[55000] [10000] 'rolsroyce'
[60000] [10000] 'ge'
[60000] [10000] 'rolsroyce'
[65000] [10000] 'ge'
[65000] [10000] 'rolsroyce'
[70000] [10000] 'ge'
[70000] [10000] 'rolsroyce'
[75000] [10000] 'ge'
[75000] [10000] 'rolsroyce'