How do I verify if a structure array is a subset of another structure array

13 views (last 30 days)
Hi,
I have two structure arrays (S1 & S2) each are nested structure arrays and I want to verify, if S1 is a sub-set of S2. The sub-set criterion are:
  • every field in S1 should exist in S2. Other way around is not necessary. This check should take the levels in nested structure into account.
  • every data on the commonly existing fields (unless it is a structure array) should be equal.
Let's take the below structures as an example:
S1.f1 = 'text';
S1.f2 = 3;
S1.f3 = struct('subF1', 0, 'subF2', 'some text');
S1.subF3 = 'extra';
S2.f1 = 'text';
S2.f2 = 3;
S2.f3 = struct('subF1', 0, 'subF2', 'some text', 'subF3', 'extra');
S2.f4 = 'also extra';
Based on the above criterion, the verification should check the following fields and data in them:
  • S1.f1 === S2.f1
  • S1.f2 === S2.f2
  • S1.f3.subF1 === S2.f3.subF1
  • S1.f3.subF2 === S2.f3.subF2
All of the above fields are common and in the same level in the nested structures. Although the field 'subF3' exists in both S1 and S2, the level in the nested structure is wrong. Therefore, it is not a common field and should cause the verification to fail.
For verification I use the matlab.unittest framework, however there is no fitting contraint to my need. The closest to what I need is the matlab.unittest.constraints.IsSubsetOf constraint, which unfortunately does not support struct types.
The workaround that I can think of is to extract the fields from S2, which exist in S1 and use the matlab.unittest.constraints.IsEqualTo constraint for the verification.
import matlab.unittest.TestCase
import matlab.unittest.constraints.IsEqualTo
testCase = TestCase.forInteractiveUse;
S2extracted = S2('allTheFieldsExistingInS1');
testCase.verifyThat(S1, IsEqualTo(S2extracted));
How can I implement the algoritm for the extraction of the fields including sub-fields?
or, is there a better way of completing the task?
  3 Comments
Rik
Rik on 29 Apr 2022
You should also watch out for values that are not equal to themselves. You might be interested in a function like ComputeNonCryptHash.
isequal(NaN,NaN)
ans = logical
0

Sign in to comment.

Accepted Answer

Jan
Jan on 29 Apr 2022
Edited: Jan on 29 Apr 2022
You have to write your own tool to test for your definition of a struct-subset. Maybe:
% [UNTESTED CODE]
function T = isStructSubset(A, B)
T = true; % Default
fA = fieldnames(A);
for k = 1:numel(fA)
dA = A.(fA{k});
if ~isfield(B, fA{k}) % B does not contain this field
T = false;
elseif isstruct(dA) % This field is a struct
dB = B.(fA{k});
if isstruct(dB) % Must be a struct in B also
T = isStructSubset(dA, dB); % [EDITED], argumentes swapped
else
T = false;
end
else % dA is not a struct:
T = isequal(B.(fA{k}), dA);
end
if ~T % Return at the first difference
return;
end
end
end
  2 Comments
Cahit Ugur
Cahit Ugur on 29 Apr 2022
Thank you for the help!
Except a tiny bug (parameter order in the recursive function call), it is perfect!
I attach the corrected code, in case someone else needs it:
% [UNTESTED CODE]
function T = isStructSubset(A, B)
T = true; % Default
fA = fieldnames(A);
for k = 1:numel(fA)
dA = A.(fA{k});
if ~isfield(B, fA{k}) % B does not contain this field
T = false;
elseif isstruct(dA) % This field is a struct
dB = B.(fA{k});
if isstruct(dB) % Must be a struct in B also
T = isStructSubset(dA, dB);
else
T = false;
end
else % dA is not a struct:
T = isequal(B.(fA{k}), dA);
end
if ~T % Return at the first difference
return;
end
end
end
Jan
Jan on 29 Apr 2022
I've fixed the bug in my code. Maybe a test for struct arrays is required also: the current version works for scalar structs only.

Sign in to comment.

More Answers (0)

Categories

Find more on Get Started with MATLAB in Help Center and File Exchange

Products


Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!