我想将两个具有不同字段名称的结构结合起来。
例如,从以下开始:
A.field1 = 1;
A.field2 = 'a';
B.field3 = 2;
B.field4 = 'b';
我想拥有:
C.field1 = 1;
C.field2 = 'a';
C.field3 = 2;
C.field4 = 'b';
有没有比使用“字段名”和 for 循环更有效的方法?
编辑:假设在字段名称冲突的情况下,我们优先考虑A.
没有碰撞,你可以做
M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
C=struct(M{:});
这是相当有效的。但是,struct重复字段名上的错误以及使用对它们进行预检查unique会导致性能下降到循环更好的程度。但这就是它的样子:
M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
[tmp, rows] = unique(M(1,:), 'last');
M=M(:, rows);
C=struct(M{:});
您可以通过假设没有冲突并在调用周围使用 try/catchstruct来优雅地降级为冲突处理案例来制作混合解决方案。
简短的回答:(setstructfields如果你有信号处理工具箱)。
官方解决方案由 Loren Shure 在她的 MathWorks 博客上发布,并由SCFrench 在此处和Eitan T 对不同问题的回答中进行了演示。但是,如果您有信号处理工具箱,一个简单的未记录函数已经可以做到这一点 - setstructfields.
help setstructfields
setstructfields Set fields of a structure using another structure
setstructfields(STRUCTIN, NEWFIELDS) Set fields of STRUCTIN using
another structure NEWFIELDS fields. If fields exist in STRUCTIN
but not in NEWFIELDS, they will not be changed.
在内部它使用fieldnames一个for循环,所以它是一个方便的函数,对本身是结构的字段进行错误检查和递归。
例子
“原始”结构:
% struct with fields 'color' and 'count'
s = struct('color','orange','count',2)
s =
color: 'orange'
count: 2
第二个结构包含 的新值'count'和新字段'shape':
% struct with fields 'count' and 'shape'
s2 = struct('count',4,'shape','round')
s2 =
count: 4
shape: 'round'
来电setstructfields:
>> s = setstructfields(s,s2)
s =
color: 'orange'
count: 4
shape: 'round'
该字段'count'已更新。字段'shape'已添加。该字段'color' 保持不变。
注意:由于该功能未记录在案,因此可能随时更改或删除。
我在 File Exchange 上找到了一个不错的解决方案: catstruct。
在不测试性能的情况下,我可以说它完全符合我的要求。它当然可以处理重复的字段。
下面是它的工作原理:
a.f1 = 1;
a.f2 = 2;
b.f2 = 3;
b.f4 = 4;
s = catstruct(a,b)
会给
s =
f1: 1
f2: 3
f3: 4
我不认为你可以用 oa 循环很好地处理冲突,我也不认为你需要避免一个。(尽管我认为效率可能是许多领域的问题......)
我使用了几年前编写的一个名为 的函数setdefaults.m,它将一个结构与另一个结构的值结合在一起,其中一个结构优先于另一个结构,以防发生冲突。
% SETDEFAULTS sets the default structure values
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S
% all the structure fields, and their values, that exist in
% SDEF that do not exist in S.
% SOUT = SETDEFAULTS(S, SDEF, OVERRIDE) does
% the same function as above, but if OVERRIDE is 1,
% it copies all fields of SDEF to SOUT.
function sout = setdefaults(s,sdef,override)
if (not(exist('override','var')))
override = 0;
end
sout = s;
for f = fieldnames(sdef)'
cf = char(f);
if (override | not(isfield(sout,cf)))
sout = setfield(sout,cf,getfield(sdef,cf));
end
end
现在我想起来了,我很确定“覆盖”输入是不必要的(你可以切换输入的顺序),尽管我不是 100% 确定这一点......所以这里有一个更简单的重写(setdefaults2.m):
% SETDEFAULTS2 sets the default structure values
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S
% all the structure fields, and their values, that exist in
% SDEF that do not exist in S.
function sout = setdefaults2(s,sdef)
sout = sdef;
for f = fieldnames(s)'
sout = setfield(sout,f{1},getfield(s,f{1}));
end
和一些样本来测试它:
>> S1 = struct('a',1,'b',2,'c',3);
>> S2 = struct('b',4,'c',5,'d',6);
>> setdefaults2(S1,S2)
ans =
b: 2
c: 3
d: 6
a: 1
>> setdefaults2(S2,S1)
ans =
a: 1
b: 4
c: 5
d: 6
在 C 中,一个结构可以有另一个结构作为它的成员之一。虽然这与您所要求的并不完全相同,但您最终可能会遇到一个结构包含另一个结构或一个结构包含两个结构的情况,这两个结构都包含您想要的部分信息。
伪代码:我不记得实际的语法。
A.field1 = 1;
A.field2 = 'a';
A.field3 = struct B;
访问:A.field3.field4;
或类似的东西。
或者你可以让 struct C 同时拥有一个 A 和一个 B:
C.A = struct A;
C.B = struct B;
访问然后类似
C.A.field1;
C.A.field2;
C.B.field3;
C.B.field4;
希望这可以帮助!
编辑:这两种解决方案都避免了命名冲突。
另外,我没有看到你的matlab标签。按照惯例,您应该编辑问题以包含该信息。