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



我有很多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)

最新更新