首页 / 知识

关于合并:在 MATLAB 中合并两个结构体的一些有效方法是什么?

2023-04-13 21:06:00

关于合并:在 MATLAB 中合并两个结构体的一些有效方法是什么?

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 标签。按照惯例,您应该编辑问题以包含该信息。


合并结构方法字段

最新内容

相关内容

热门文章

推荐文章

标签云

猜你喜欢