Проверка двух структур MATLAB на равные, даже если содержимое поля транспонировано - PullRequest
1 голос
/ 27 января 2020

Мне нужно проверить, равны ли две структуры 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

Одно из решений, прежде чем проверять равенство, я мог бы l oop над полями одной структуры и убедитесь, что размер совпадает с полями другой структуры, транспонируя при необходимости. Тем не менее, это не очень эффективно, и мне нравится избегать петель, когда я могу. Есть ли функция, аналогичная isequal, которая является транспозиционно-инвариантной?

1 Ответ

2 голосов
/ 27 января 2020

А пока go Я написал собственное рекурсивное сравнение вложенных структур (в основном, чтобы увидеть, где переменные различаются), и вам нужно всего лишь заменить isequal(a,b) на isequal(a,b) || isequal(a,b') в одной строке кода, чтобы получить транспонирование. инвариантное равное поведение. Код выдает ошибку, если две переменные не равны, а также говорит, где.

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
...