我有很多mat文件,每个文件都包含一个内部结构相同的结构数组s
。以下是从加载单个文件中获得的s
结构数组的一个最小示例:
s(1).A.a=rand(3);
s(1).A.b=rand(4);
s(1).B =1;
s(2).A.a=rand(3);
s(2).A.b=rand(4);
s(2).B =10;
在实践中,结构阵列具有100个元素,以及数十个字段和子字段。请不要评论按原样保存文件的选择。它不在我的控制范围内,这里的问题是如何处理这些文件中的信息。
我想最终对这些结构数组的每个子字段的所有信息求平均值,因此逻辑步骤是对它们求和(然后除以文件数(。
我目前的解决方案是:
% initialize arrays of the same inner structure as `s`
sum_s_A_a=zeros(size(s(1).A.a,1),size(s(1).A.a,2),numel(s));
sum_s_A_b=zeros(size(s(1).A.b,1),size(s(1).A.b,2),numel(s));
sum_s_B=zeros(1,numel(s));
for jj=1:100 % loop over all 100 files (just for the example)
% load here each file that contains s
for ii=1:numel(s) ; % loop each element in s and add it to sum_s
sum_s_A_a(:,:,ii) = sum_s_A_a(:,:,ii) + s(ii).A.a;
sum_s_A_b(:,:,ii) = sum_s_A_b(:,:,ii) + s(ii).A.b;
sum_s_B(ii) = sum_s_B(ii) + s(ii).B;
end
end
这是非常不实际的,因为s
中有几十个字段和子字段,但上面的最小示例适用于";"单个文件";如果您使用如上所定义的s
我只想以与上面的for循环类似的方式总结所有这些文件的信息,但不需要将字段和子字段的所有名称写下来并硬编码为数组名称,如果可能的话,也不需要for循环。
我不介意信息的最终容器是结构体、单元格还是数组。
从您的示例开始,为了求和所有A
字段并返回一个数字数组,这里有一种不使用循环的方法:
function result = sumstruct (varargin)
v = [varargin{:}];
s = [v.A];
result = sum([s.tot1], 2);
end
并称之为:
result = sumstruct (s1, s2, s3);
编辑:
但是,如果您还想对其他字段及其子字段求和,并将它们组合为一个结构,则需要使用循环或cellfun
。这里有一个递归减少嵌套结构的解决方案:
function result = reduce(fcn, varargin)
fcns0 = {@(x)cat(3, x{:}), @(x)x};
switcher0 = @(tf, s)fcns0{tf+1}(s);
fcns = {@(s)fcn(s), @(s)reduce(fcn, s{:})};
switcher = @(tf, s)fcns{tf+1}(s);
c = cellfun(@(x){struct2cell(x)}, varargin);
s0 = cat(3, c{:});
s1 = reshape(s0, [], numel(varargin));
s2 = cellfun(@(x){switcher0(isstruct(x{1}), x)}, num2cell(s1, 2));
s3 = reshape(s2, size(c{1}));
s4 = cellfun(@(c){switcher(iscell(c), c)}, s3);
fnames = fieldnames(varargin{1});
result = cell2struct(s4, fnames, 1);
end
第一个参数是用于减少的函数句柄,其余参数是结构数组。
使用循环加载所有文件并使用reduce:
c = cell (1, 100);
for i = 1:100
c{i} = load('file');
end
result = reduce(@(x)sum(x, 3), c{:});
result = reduce(@(x)x ./ 100, result);
或者,您可以增量加载文件并执行reduce:
result = [];
for i = 1:100
s = load('file');
if i == 1
result = s;
else
result = reduce(@(x)sum(x, 3), result, s);
end
end
result = reduce(@(x)x ./ 100, result);
注意,这里的归约函数应该沿着数组的第三维度执行,因此它被写为sum(x, 3)
。