问题
I have a tree structure in matlab like this:
node =
sub: [1x4 struct]
where each sub is also a node.
node.sub(1) =
sub: [1x4 struct]
etc. with leaf nodes having empty sub. Suppose I have a node and I am traversing down the tree. Is there any way to check if the node 'object' is the same as any in the tree? I am not talking about the value being the same. I want the 'object' to be the same.
For eg.:
mynode = tree.sub(1).sub(1);
isobjectequal(mynode, tree.sub(1).sub(1))
回答1:
A struct
in MATLAB is not technically an "object" in the sense that you're talking about it. If I create a struct and then assign it as a field within another struct, the two are now uncoupled. Any changes made to the first struct will not be reflected in the copy we just made.
a = struct('a', 2);
b = struct('b', a);
a.a = 3
% b.b.a == 2
You can really only reliably check that the values of two struct
s are equal.
If you actually want to verify that the two struct
s that you're comparing were created in the same way, you could go through the struct
recursively and determine whether the memory location of each element is the same in both structs. This would imply that the struct is both equal and they were created with the same underlying data.
For a very simple non-deeply nested struct this could look something like this.
function bool = isSameStruct(A, B)
fmt = get(0, 'Format');
format debug;
memoryLocation = @(x)regexp(evalc('disp(x)'), '(?<=pr\s*=\s*)[a-z0-9]*', 'match');
if isequaln(A, B)
bool = true;
elseif ~isequal(sort(fieldnames(A)), sort(fieldnames(B)))
bool = false;
else
fields = fieldnames(A);
bool = true;
for k = 1:numel(fields)
if ~isequal(memoryLocation(A.(fields{k})), memoryLocation(B.(fields{k})))
bool = false;
break;
end
end
end
format(fmt);
end
Update
An alternative is to use actual handle
objects for your nodes. A basic class would look like this.
classdef Node < handle
properties
Value
Children
end
methods
function self = Node(value)
self.Value = value;
end
function addChild(self, node)
self.Children = cat(2, self.Children, node)
end
end
end
回答2:
If you are searching for "reference-equality" I guess you should use handle objects:
Use isequal when you want to determine if different handle objects have the same data in all object properties. Use == when you want to determine if handle variables refer to the same object.
treeTest.m
function treeTest()
root = TreeItem('Root');
child = TreeItem('Child');
grandChild = TreeItem('GrandChild');
grandGrandChild = TreeItem('GrandGrandChild');
grandGrandChild2 = TreeItem('GrandGrandChild');
root.Children{end+1} = child;
child.Children{end+1} = grandChild;
grandChild.Children{end+1} = grandGrandChild;
grandChild.Children{end+1} = grandGrandChild2;
findItem(root, grandGrandChild2)
function findItem(tree, childToFind)
if ~numel(tree.Children)
return;
end
disp(['Traversing in ', tree.Name]);
for i=1:numel(tree.Children)
disp(['Iteration step: ', num2str(i)])
if tree.Children{i} == childToFind
disp(['Found! Name is ', tree.Children{i}.Name]);
return;
end
findItem(tree.Children{i}, childToFind);
end
end
end
TreeItem.m
classdef TreeItem < handle
properties
Name;
Children;
end
methods
function obj = TreeItem(name)
obj.Name = name;
obj.Children = {};
end
end
end
The output is
Traversing in Root
Iteration step: 1
Traversing in Child
Iteration step: 1
Traversing in GrandChild
Iteration step: 1
Iteration step: 2
Found! Name is GrandGrandChild
As you can see the two grand-grand-child object are equal in terms of properties, but the Iteration step: 2
entry on the output proves, that the first grand-grand-child was skipped, because the function is searching for the second one.
The difference between isequal
and ==
:
>> grandGrandChild = TreeItem('GrandGrandChild');
grandGrandChild2 = TreeItem('GrandGrandChild');
>> isequal(grandGrandChild, grandGrandChild2)
ans = 1
>> grandGrandChild == grandGrandChild2
ans = 0
来源:https://stackoverflow.com/questions/38396319/equality-of-structure-objects