对具有相同内部结构的结构数组中的字段求和
summing fields in struct arrays that have the same inner structure
我有很多 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
中有许多字段和子字段,但是 如果您使用 上面的最小示例适用于“单个文件”的情况=12=] 如上定义
我想以类似于上面 for 循环的方式对所有这些文件的信息求和,但不写下所有字段和子字段的名称并将其硬编码到数组名称中,如果可能没有 for 循环。
我不介意信息的最终容器是结构、单元还是数组。
从您的示例开始,以便对所有 A
字段求和 return 这里的数字数组是一种不使用循环的方法:
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)
。
我有很多 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
中有许多字段和子字段,但是 如果您使用 上面的最小示例适用于“单个文件”的情况=12=] 如上定义
我想以类似于上面 for 循环的方式对所有这些文件的信息求和,但不写下所有字段和子字段的名称并将其硬编码到数组名称中,如果可能没有 for 循环。
我不介意信息的最终容器是结构、单元还是数组。
从您的示例开始,以便对所有 A
字段求和 return 这里的数字数组是一种不使用循环的方法:
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)
。