对具有相同内部结构的结构数组中的字段求和

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)