What are some efficient ways to combine two structures in MATLAB?
我想结合两个具有不同字段名称的结构。
例如以:
开头
1 2 3 4 5
| A.field1 = 1;
A.field2 = 'a';
B.field3 = 2;
B.field4 = 'b'; |
我想要:
1 2 3 4
| C.field1 = 1;
C.field2 = 'a';
C.field3 = 2;
C.field4 = 'b'; |
有没有比使用"字段名"和 for 循环更有效的方法?
编辑:假设在字段名称冲突的情况下,我们优先使用 A.
没有碰撞,你可以做
1 2
| M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
C=struct(M{:}); |
这是相当有效的。但是,重复字段名上的 struct 错误以及使用 unique 对它们进行预检查会导致性能下降到循环更好的程度。但它看起来像这样:
1 2 3 4 5 6
| M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
[tmp, rows] = unique(M(1,:), 'last');
M=M(:, rows);
C=struct(M{:}); |
您可以通过假设没有冲突并在对 struct 的调用周围使用 try/catch 来优雅地降级到冲突处理情况来制定混合解决方案。
简答:setstructfields(如果您有信号处理工具箱)。
官方解决方案由 Loren Shure 在她的 MathWorks 博客上发布,SCFrench 在这里和 Eitan T\\'s 对另一个问题的回答中进行了演示。但是,如果您有信号处理工具箱,一个简单的未记录的函数已经可以做到这一点 - setstructfields.
help setstructfields
1 2 3 4
| 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 循环,因此它是一个方便的函数,对本身是结构的字段进行错误检查和递归。
例子
"原始"结构:
1 2 3 4 5 6
| % struct with fields 'color' and 'count'
s = struct('color','orange','count',2)
s =
color: 'orange'
count: 2 |
包含 'count' 的新值和新字段 'shape':
的第二个结构
1 2 3 4 5 6
| % struct with fields 'count' and 'shape'
s2 = struct('count',4,'shape','round')
s2 =
count: 4
shape: 'round' |
调用 setstructfields:
1 2 3 4 5
| >> s = setstructfields(s,s2)
s =
color: 'orange'
count: 4
shape: 'round' |
字段 'count' 已更新。添加字段 'shape'。字段 'color' 保持不变。
注意:由于该函数未记录在案,因此可能会随时更改或删除。
我在文件交换上找到了一个不错的解决方案:catstruct.
在不测试性能的情况下,我可以说它完全符合我的要求。
它当然可以处理重复的字段。
这是它的工作原理:
1 2 3 4 5 6
| a.f1 = 1;
a.f2 = 2;
b.f2 = 3;
b.f4 = 4;
s = catstruct(a,b) |
会给
1 2 3 4 5
| s =
f1: 1
f2: 3
f3: 4 |
我不认为你可以在没有循环的情况下很好地处理冲突,我也认为你不需要避免冲突。 (虽然我认为效率可能是许多领域的问题...)
我使用我几年前写的一个名为 setdefaults.m 的函数,它将一个结构与另一个结构的值结合在一起,在发生冲突时一个优先于另一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| % 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):
1 2 3 4 5 6 7 8 9 10
| % 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 |
和一些测试它的样本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| >> 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 中,一个结构体可以有另一个结构体作为它的成员之一。虽然这与您所问的不完全相同,但您最终可能会遇到一个结构包含另一个结构的情况,或者一个结构包含两个结构,这两个结构都包含您想要的部分信息。
伪代码:我不记得实际的语法。
1 2 3
| A.field1 = 1;
A.field2 = 'a';
A.field3 = struct B; |
访问:
A.field3.field4;
或者类似的东西。
或者你可以让 struct C 同时包含一个 A 和一个 B:
1 2
| C.A = struct A;
C.B = struct B; |
具有访问权限,然后类似于
1 2 3 4
| C.A.field1;
C.A.field2;
C.B.field3;
C.B.field4; |
希望这有帮助!
编辑:这两种解决方案都避免了命名冲突。
另外,我没有看到你的 matlab 标签。按照惯例,您应该编辑问题以包含该信息。
|