即使字段内容被转置,检查两个 MATLAB 结构是否相等
Checking two MATLAB structs as equal even if field contents are transposed
我需要检查两个 MATLAB 结构(所有字段名和值)是否相等。这两个结构都是结构的结构。有时,这些结构除了一件事外是相等的:一个结构中的字段值是另一个结构中字段值的转置。
如果我使用函数 isequal
检查两个结构是否相等,如果字段内容被转置,我会得到一个否定的结果。
示例:
cfg1.x = {'a' 'b'};
cfg1.y.z = {'c' 'd'};
cfg2.x = {'a' 'b'}';
cfg2.y.z = {'c' 'd'}';
isequal(cfg1, cfg2)
>> isequal(cfg1, cfg2)
ans =
logical
0
一种解决方案是在检查相等性之前,我可以遍历一个结构的字段,并在必要时通过转置确保大小调整与另一个结构的字段对齐。然而,这似乎不是很有效,我喜欢尽可能避免循环。有没有类似于isequal
的转置不变的函数?
前段时间我自己编写了嵌套结构的递归比较(主要是为了查看变量的不同之处),您只需在代码的一行中将 isequal(a,b)
替换为 isequal(a,b) || isequal(a,b')
即可获得转置不变的 isequal 行为。如果两个变量不相等,代码会抛出错误,并指出 where.
function compare(A, B, path)
% Compares two variables, A and B, for equality with a recursive test.
% Throws and error if not equal, otherwise just returns.
assert(nargin >= 2, 'Not enough parameters.');
if nargin == 2
path = '';
end
their_class = class(A);
assert(strcmp(their_class, class(B)), '%s, A and B do not have the same class.', path);
if isnumeric(A) || islogical(A)
% here we also treat NaN as equal since we compare the content of two variables
assert(isequaln(A, B), '%s, Array A and B are not equal.', path);
% replace isequaln(A, B) with isequaln(A, B) || isqualn(A, B') to get transpose-invariance of comparison
else
switch their_class
case 'cell'
compare_cells(A, B, path);
case 'struct'
compare_structs(A, B, path);
case 'char'
assert(strcmp(A, B), '%s, Char array A and B is not equal.', path);
otherwise
error('%s, Comparison of class %s not yet supported.', path, their_class);
end
end
end
function compare_cells(A, B, path)
% Assuming A and B are both cell array, compare them, calling back to the
% main function if needed.
assert(isequal(size(A), size(B)), 'Size of cell arrays not equal.');
for i = 1 : numel(A)
compare(A{i}, B{i}, [path, sprintf('/cell:%d', i)]);
end
end
function compare_structs(A, B, path)
% Assuming A and B are both structs, compare them, calling back to the main
% function if needed.
fields = fieldnames(A);
assert(all(strcmp(unique(fields), unique(fieldnames(B)))), 'Number of names of struct fields not equal.');
for i = 1 : length(fields)
field = fields{i};
a = A.(field);
b = B.(field);
compare(a, b, [path, sprintf('/field:%s', field)]);
end
end
我需要检查两个 MATLAB 结构(所有字段名和值)是否相等。这两个结构都是结构的结构。有时,这些结构除了一件事外是相等的:一个结构中的字段值是另一个结构中字段值的转置。
如果我使用函数 isequal
检查两个结构是否相等,如果字段内容被转置,我会得到一个否定的结果。
示例:
cfg1.x = {'a' 'b'};
cfg1.y.z = {'c' 'd'};
cfg2.x = {'a' 'b'}';
cfg2.y.z = {'c' 'd'}';
isequal(cfg1, cfg2)
>> isequal(cfg1, cfg2)
ans =
logical
0
一种解决方案是在检查相等性之前,我可以遍历一个结构的字段,并在必要时通过转置确保大小调整与另一个结构的字段对齐。然而,这似乎不是很有效,我喜欢尽可能避免循环。有没有类似于isequal
的转置不变的函数?
前段时间我自己编写了嵌套结构的递归比较(主要是为了查看变量的不同之处),您只需在代码的一行中将 isequal(a,b)
替换为 isequal(a,b) || isequal(a,b')
即可获得转置不变的 isequal 行为。如果两个变量不相等,代码会抛出错误,并指出 where.
function compare(A, B, path)
% Compares two variables, A and B, for equality with a recursive test.
% Throws and error if not equal, otherwise just returns.
assert(nargin >= 2, 'Not enough parameters.');
if nargin == 2
path = '';
end
their_class = class(A);
assert(strcmp(their_class, class(B)), '%s, A and B do not have the same class.', path);
if isnumeric(A) || islogical(A)
% here we also treat NaN as equal since we compare the content of two variables
assert(isequaln(A, B), '%s, Array A and B are not equal.', path);
% replace isequaln(A, B) with isequaln(A, B) || isqualn(A, B') to get transpose-invariance of comparison
else
switch their_class
case 'cell'
compare_cells(A, B, path);
case 'struct'
compare_structs(A, B, path);
case 'char'
assert(strcmp(A, B), '%s, Char array A and B is not equal.', path);
otherwise
error('%s, Comparison of class %s not yet supported.', path, their_class);
end
end
end
function compare_cells(A, B, path)
% Assuming A and B are both cell array, compare them, calling back to the
% main function if needed.
assert(isequal(size(A), size(B)), 'Size of cell arrays not equal.');
for i = 1 : numel(A)
compare(A{i}, B{i}, [path, sprintf('/cell:%d', i)]);
end
end
function compare_structs(A, B, path)
% Assuming A and B are both structs, compare them, calling back to the main
% function if needed.
fields = fieldnames(A);
assert(all(strcmp(unique(fields), unique(fieldnames(B)))), 'Number of names of struct fields not equal.');
for i = 1 : length(fields)
field = fields{i};
a = A.(field);
b = B.(field);
compare(a, b, [path, sprintf('/field:%s', field)]);
end
end