代码之家  ›  专栏  ›  技术社区  ›  KennyMorton

在Matlab中,将两种结构结合起来的有效方法是什么?

  •  23
  • KennyMorton  · 技术社区  · 17 年前

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

    例如,从以下内容开始:

    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 .

    5 回复  |  直到 12 年前
        1
  •  18
  •   SCFrench    17 年前

    没有碰撞,你可以做到

    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/catch来实现混合解决方案。 结构 优雅地降级为冲突处理案例。

        2
  •  8
  •   Community Mohan Dere    9 年前

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


    官方解决方案由Loren Shure发布于 her MathWorks blog ,并由 SCFrench here 而在 Eitan T's answer to a different question . 但是,如果您有信号处理工具箱,那么一个简单的未记录的函数已经做到了这一点。- 设置结构字段 .

    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 和A 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'
    

    打电话 设置结构字段 :

    >> s = setstructfields(s,s2)
    s = 
        color: 'orange'
        count: 4
        shape: 'round'
    

    田地 “伯爵” 更新的 . 田地 “形” 补充 . 田地 'color' 保持不变 .

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

        3
  •  5
  •   Dennis Jaheruddin    12 年前

    我找到了一个不错的 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
    
        4
  •  4
  •   Jason S    17 年前

    我认为你不需要循环就能很好地处理冲突,我也不认为你需要避免循环。(尽管我认为效率可能是许多领域的一个问题…)

    我用了几年前写的一个函数 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
    
        5
  •  2
  •   pbh101    17 年前

    在C中,一个结构可以有另一个结构作为它的成员之一。虽然这与您所要求的不完全相同,但您最终可能会遇到一个结构包含另一个结构的情况,或者一个结构包含两个结构,这两个结构都包含您想要的部分信息。

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

    A.field1 = 1;
    A.field2 = 'a';
    A.field3 = struct B;
    

    访问: A.field3.field4;

    或者类似的东西。

    或者您可以让结构C同时容纳A和B:

    C.A = struct A;
    C.B = struct B;
    

    有了门禁

    C.A.field1;
    C.A.field2;
    C.B.field3;
    C.B.field4;
    

    希望这有帮助!

    编辑:这两种解决方案都避免了命名冲突。

    而且,我没看到你的 matlab 标签。按照惯例,您应该编辑问题以包含该信息。