使用MATLAB,除了使用嵌套FOR循环的强力技术之外,我很好奇是否有更优雅的方法来提取X&来自我在下面显示的示例数据结构的Y数据。我无法使用bsxfun,arrayfun或strucfun在MATLAB中设计一种优雅的方法。
% Create an example of the input structure that I need to parse
for i =1:100
setName = ['n' num2str(i)];
for j = 1:randi(10,1)
repName = ['n' num2str(j)];
data.sets.(setName).replicates.(repName).X = i + randn();
data.sets.(setName).replicates.(repName).Y = i + randn();
end
end
clearvars -except data
% Brute force technique using nested FOR Loops to extract X & Y from this
% nested structure for easy plotting. Is there a better way to extract the
% X & Y values created above without using FOR loops?
n = 1;
setNames = fieldnames(data.sets);
for i =1:length(setNames)
replicateNames = fieldnames(data.sets.(setNames{i}).replicates);
for j = 1:length(replicateNames)
X(n) = data.sets.(setNames{i}).replicates.(replicateNames{j}).X;
Y(n) = data.sets.(setNames{i}).replicates.(replicateNames{j}).Y;
n = n+1;
end
end
scatter(X,Y);
答案 0 :(得分:1)
MATLAB最适用于数组/矩阵(无论是数值数组,结构数组,单元数组,对象数组等)。该语言提供了轻松切片和索引到数组的构造。
因此,MATLAB中的惯用方法是创建non-scalar structure array,而不是deeply nested structure。
例如,让我们首先将嵌套结构转换为2D结构数组,其中第一个维度表示"复制",第二个维度表示"设置":
ds = struct('X',[], 'Y',[]);
sets = fieldnames(data.sets);
for i=1:numel(sets)
reps = fieldnames(data.sets.(sets{i}).replicates);
for j=1:numel(reps)
ds(j,i) = data.sets.(sets{i}).replicates.(reps{j});
end
end
结果是一个10乘100的结构数组,每个数组有两个字段X和Y:
>> ds
ds =
10x100 struct array with fields:
X
Y
在原始结构中访问data.sets.n99.replicates.n9
将等同于新结构中的ds(9,99)
。
>> data.sets.n99.replicates.n9
ans =
X: 100.3616
Y: 98.8023
>> ds(9,99)
ans =
X: 100.3616
Y: 98.8023
这个新结构的好处是可以使用数组索引表示法和comma-separated lists轻松访问它。所以我们可以像你一样提取X和Y向量:
XX = [ds.X]; % or XX = cat(2, ds.X)
YY = [ds.Y];
scatter(XX, YY, 1)
因此,如果您可以控制构建结构,我将按照上面的描述进行设计。否则,使用dynamic field names的代码中的双重for循环是从中提取值的最佳方法。
你可能会写一堆structfun
互相呼叫,但这不是最易读的代码。以下是我想要展平嵌套结构的内容:
D = structfun(@(n) ...
structfun(@(nn) [nn.X nn.Y], n.replicates, 'UniformOutput',false), ...
data.sets, 'UniformOutput',false);
可以使用较少的嵌套字段访问生成的结构:
>> D.n99.n9
ans =
100.3616
98.8023
原始版本略胜一筹,但如果没有一些for循环仍然不能轻易遍历。
答案 1 :(得分:-1)
因为我们经常被给予"来自我们无法控制的来源(其他业务部门,客户等)的深层嵌套结构,有时婴儿必须做婴儿必须做的事情。这是一个似乎可以完全展平嵌套结构的黑客攻击。如果其中一个问题被删除,也会发布到here。 。版权所有Carl Witthoft遵循通常的GPL-3规则。
% struct2sims converter
function simout = struct2sims(structin)
fnam = fieldnames(structin);
for jf = 1:numel(fnam)
subnam = [inputname(1),'_',fnam{jf}];
if isstruct(structin.(fnam{jf}) ) ,
% need to dive; build a new variable that's not a substruct
eval(sprintf('%s = structin.(fnam{jf});', fnam{jf}));
eval(sprintf('simtmp = struct2sims(%s);',fnam{jf}) );
% try removing the struct before getting any farther...
simout.(subnam) = simtmp;
else
% at bottom, ok
simout.(subnam) = structin.(fnam{jf});
end
end
% need to unpack structs here, after each level of recursion
% returns...
subfnam = fieldnames(simout);
for kf = 1:numel(subfnam)
if isstruct(simout.(subfnam{kf}) ),
subsubnam = fieldnames(simout.(subfnam{kf}));
for fk = 1:numel(subsubnam)
simout.([inputname(1),'_',subsubnam{fk}])...
= simout.(subfnam{kf}).(subsubnam{fk}) ;
end
simout = rmfield(simout,subfnam{kf});
end
end
% if desired write to file with:
% save('flattened','-struct','simout');
end