为什么MATLAB对结构数组赋值中的字段顺序敏感?

时间:2016-04-28 20:45:21

标签: arrays matlab struct matlab-struct

首先,我将A指定为结构,并指定其他两个结构:B具有相同的元素顺序,C具有不同的元素顺序。

A.x = 11;
A.y = 11;

B.x = 21;
B.y = 22;

C.y = 31;   %// Note that I am specifying
C.x = 32;   %// y first and x second

A = B;      %// Works fine
A = C;      %// Works fine

A分配给BC的工作,这是我期望从结构中获得的行为 - 元素的顺序无关紧要。

现在我将A指定为结构数组而不是结构,并尝试将其中一个元素分别指定给BC

clear;

A(1).x = 11;
A(1).y = 12;

B.x = 21;
B.y = 22;

C.y = 31;   %// Note that I am specifying
C.x = 32;   %// y first and x second

A(1) = B;   %// Works fine
A(1) = C;   %// Error!

突然,MATLAB抱怨错误:

  

不同结构之间的下标分配

有没有人知道为什么会这样,以及如何以优雅的方式解决它?

2 个答案:

答案 0 :(得分:11)

可能会发生这种情况,因为对struct的内置subsasgn调用可能只是比较源{n}和目标结构的fieldnames(取决于字段顺序)的输出并且在比较之前不执行任何排序(可能是因为为每个分配排序两个单元阵列的性能损失)。如果存在差异(如您所示的情况),则会引发错误并中止分配。

解决此问题的最简单方法是在源结构上使用orderfields,并指定您希望使用第二个输入参数使排序与目标结构匹配。

A = struct('x', 11, 'y', 12);
B = struct('y', 21, 'x', 22);

%// Ensure that the fields of B are in the same order as they are in A
A(1) = orderfields(B, A);

在我个人看来,我认为subsasgn应该为struct输入执行此操作,因为操作相对较快(因为没有排序和struct的基础数据未被复制)但允许更灵活的struct作业。

另一方面,如果您没有直接分配,只是想追加两个structs,那么字段的顺序不会问题和字段的顺序是从遇到的第一个struct继承的。

%// Uses the ordering of the fields in A
C = cat(1, A, B);

%// Uses the ordering of the fields in B
D = cat(1, B, A);

<强>更新

我刚注意到你在原帖中显示以下内容有效,因为订单无关紧要。

A = B;

这是有效的,因为此赋值不依赖于A 的数据类型。在这种情况下,MATLAB 移除 A在分配之前引用的数据,然后重新分配 A它到{{{ 1}}。我们甚至可以使B成为一个单元格数组并执行上述任务,没有任何问题。

A

此作业不会调用A = cell(2); B = struct('y', 21, 'x', 22); %// No errors here! A = B; (仅处理下标分配),因此不会出现您遇到的问题。

答案 1 :(得分:4)

我过去解决这个问题的一种方法是创建结构的“null”版本,类似于为对象创建构造函数。

%% define null struct
null_struct.x = 0;
null_struct.y = 0;

%% Now, initialize all structs with it
A=null_struct;
B=null_struct;
C=null_struct;

%% You can even initialize large arrays
Z(1:1000, 1:1000) = null_struct;

然后,您可以按照自己喜欢的顺序填充结构。您甚至可以将“空”结构传递给函数,并允许函数填充值,并且函数不必注意赋值的顺序。

A(1).x = 11;
A(1).y = 12;

B.x = 21;
B.y = 22;

C.y = 31;   % Note that I'm specifying
C.x = 32;   % y first and x second

A(1) = B;   % Works fine
A(1) = C;   % Also works fine!

初始化数据结构是非常好的编程实践,对于大型struct数组,它实际上节省了大量时间来预先进行初始化。即使你必须初始化超过需要的元素,并在最后截断数组,通常也是值得的。

编辑:您的错误说明: MATLAB在原始示例中抛出错误的原因是内部(在C代码后端),MATLAB将字段名称存储在有序的字符串数组中,并将名称映射到相应的字段索引。当您执行

之类的作业时
A = C;

MATLAB首先检查两个字段名列表是否匹配,这要求列表相同,包括相同的顺序。如果是,那么它按照从rhs到lhs的顺序映射字段值。