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

例如,从以下内容开始:

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

其他提示

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


官方解决方案由 Loren Shure 发布于 她的 MathWorks 博客, ,并证明了 SC法语在这里 并在 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' 保持不变.

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

我找到了一个不错的 文件交换的解决方案:猫结构体.

在不测试性能的情况下,我可以说它完全符合我的要求。它当然可以处理重复的字段。

下面是它的工作原理:

a.f1 = 1;
a.f2 = 2;
b.f2 = 3;
b.f4 = 4;

s = catstruct(a,b)

会给

s = 

    f1: 1
    f2: 3
    f3: 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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top