在MATLAB中组合两个结构有哪些有效的方法?

时间:2008-09-02 00:10:45

标签: matlab merge structure field

我想组合两个具有不同字段名称的结构。

例如,从:

开始
A.field1 = 1;
A.field2 = 'a';

B.field3 = 2;
B.field4 = 'b';

我想:

C.field1 = 1;
C.field2 = 'a';
C.field3 = 2;
C.field4 = 'b';

有没有比使用“fieldnames”和for循环更有效的方式?

编辑:我们假设在字段名称冲突的情况下,我们会优先考虑A

5 个答案:

答案 0 :(得分:18)

没有碰撞,你可以做

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{:});

您可以通过假设没有冲突并使用围绕调用struct的try / catch来优雅地降级到冲突处理案例来创建混合解决方案。

答案 1 :(得分:8)

简短回答: setstructfields (如果您有信号处理工具箱)。


官方解决方案由Loren Shure在her MathWorks blog上发布,由SCFrench hereEitan T's answer to a different question演示。但是,如果你有信号处理工具箱,一个简单的未记录的函数已经这样做了 - 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.

在内部,它使用fieldnamesfor循环,因此它是一个便利函数,对自身结构化的字段进行错误检查和递归。

示例

&#34;原作&#34;结构:

% 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' 保持不变

注意:由于该功能未记录,因此可能随时更改或删除。

答案 2 :(得分:5)

我找到了一个不错的solution on 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

答案 3 :(得分:4)

我认为你不能在没有循环的情况下处理冲突,我认为你也不需要避免冲突。 (虽然我认为效率可能是许多领域的问题......)

我使用了几年前写的一个名为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

答案 4 :(得分:2)

在C中,struct可以将另一个struct作为其成员之一。虽然这与你提出的问题并不完全相同,但你最终可能会遇到一个结构包含另一个结构的情况,或者一个结构包含两个结构,这两个结构都包含你想要的信息的一部分。

psuedocode:我不记得实际的语法。

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