连接元胞数组中结构的(子)字段
Concatenating (sub)fields of structs in a cell array
我有一个 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
但我不能完全让这种方法在更一般的上下文中工作(即具有不同的字段)。
我找到了一种使用 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
通常不是一个好主意。我很好奇不同的解决方案。
编辑:不需要递归,如@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
您可能需要使用函数 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);
我有一个 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
但我不能完全让这种方法在更一般的上下文中工作(即具有不同的字段)。
我找到了一种使用 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
通常不是一个好主意。我很好奇不同的解决方案。
编辑:不需要递归,如@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
您可能需要使用函数 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);