【问题标题】:Concatenating (sub)fields of structs in a cell array连接元胞数组中结构的(子)字段
【发布时间】:2016-06-08 03:48:47
【问题描述】:

我有一个 Matlab 对象,它是一个包含具有几乎相同结构的结构的元胞数组,我想以编程方式获取所有元胞数组元素的结构的(子)字段。

比如我们取test

test = {struct('a',struct('sub',1)), struct('a',struct('sub',2),'b',1)};

这将创建一个具有以下结构的元胞数组:

cell-element 1: a --> sub --> 1
cell-element 2: a --> sub --> 2
                  \-> b --> 1

可以看出test的元素结构并不完全相同,而是相似。如何获取单元格元素的 a.sub 字段的所有值。我可以在这个特定问题中获得它们

acc=zeros(1,numel(test));
for ii=1:numel(test)
   acc(ii) = test{ii}.a.sub;
end

但我不能完全让这种方法在更一般的环境中工作(即具有不同的字段)。

【问题讨论】:

  • “拥有不同的字段”是什么意思?不同类型的字段值?不同的字段名称?
  • 我的意思是不是访问每个元素的字段.a.sub 而是访问不同的字段,例如。 .some.thing.else(我没有包含在我的小示例单元数组中)
  • getfield 或多或少等同于动态字段名称.(variable),不能处理像a.sub 这样的字段名称。因此,如果不以某种方式在. 上拆分a.sub,我将无法直接使用它。
  • 好的,也许我应该把这个放在答案中......

标签: matlab cell-array


【解决方案1】:

您可能想使用函数getfield

%//Data to play with
test = {struct('a',struct('sub',1)), struct('a',struct('sub',2),'b',1)};

%//I'm interested in these nested fields
nested_fields = {'a', 'sub'};

%//Scan the cell array to retrieve the data array
acca = cellfun(@(x) getfield(x, nested_fields{:}), test);

如果您的数据不能保证所有元素的类型和大小都相同,那么您需要输出一个元胞数组:

%//Scan the cell array to retrieve the data cell array
accc = cellfun(@(x) getfield(x, nested_fields{:}), test, 'UniformOutput', false);

稍后编辑

如果想为每个单元格元素使用不同的嵌套字段集,那么:

%//nested_fields list should have the same size as test
nested_fields = {{'a','sub'}, {'b'}};
accm = cellfun(@(x,y) getfield(x,y{:}), test, nested_fields, 'UniformOutput', false);

【讨论】:

  • 如果我们想为第一个结构访问嵌套字段a.sub,而只为第二个结构访问b?编辑:啊,也许nested_fields{:} 会自动为我们处理这个问题?不错!
  • @dfri 取决于你想如何表达。不过好吧,我会更新这个案例的答案。
【解决方案2】:

编辑:不需要递归,如@CST-link:s answer所示;原生 getfield 函数可以巧妙地展开一个单元格数组作为其第二个参数,例如getfield(foo{i}, fields{:}) 而不是在下面我的旧答案中调用递归函数。但是,我将在下面留下递归解决方案,因为它可能在问题的上下文中具有一些价值。


您可以构建自己的 getField 递归版本,采用一个单元格数组。

function value = getFieldRec(S,fields)
  if numel(fields) == 1 
    value = getfield(S, fields{1});
  else
    S = getfield(S,fields{1})
    fields{1} = [];
    fields = fields(~cellfun('isempty',fields));
    value = getFieldRec(S,fields);
  end
end

示例用法:

foo = {struct('a',struct('sub',1)), ...
  struct('a',struct('sub',2),'b',3), ...
  struct('c',struct('bar',7),'u',5)};
accessFields = {'a.sub', 'b', 'c.bar'};

values = zeros(1,numel(foo));
for i = 1:numel(foo)
  fields = strsplit(accessFields{i},'.');
  values(i) = getFieldRec(foo{i},fields);
end

结果如下

values =

     1     3     7

【讨论】:

    【解决方案3】:

    我找到了一种使用eval的方法:

    function out = catCellStructSubField(cellStruct, fieldName)
    out = zeros(1,numel(cellStruct));
    for ii = 1:numel(cellStruct)
       out(ii) = eval(['cellStruct{ii}.' fieldName]);
    end
    

    它可以在我的测试示例中使用,如下所示:

    catCellStructSubField(test, 'a.sub')
    

    动态字段名称 (cellStruct{ii}.(fieldName)) 不起作用,因为我正在访问子字段。

    我知道eval 通常是个坏主意。我很好奇不同的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      相关资源
      最近更新 更多