Efficient indexing with nested object and object arrays

17 views (last 30 days)
I have an object structure that is intended to represent a physical system and be easy to understand and interact with. This requires that I use an object array with each object containing other objects, structs, and properties.
My structure is close to the following:
% How I would like to access nested values, where out is an array
[out] = parentObj.myObjArray.myObj.myStruct.myProperty;
% alternatively
[out] = parentObj.myObjArray(:).myObj.myStruct.myProperty;
Of course, either of these results in the following error: Expected one output from a curly brace or dot indexing expression, but there were N results.
However, the following works without issue:
% Step through each object in objArray and get propery value
for i=1:length(myObjArray)
out(i) = parentObj.myObjArray(i).myObj.myStruct.myProperty;
end
% Then do something with 'out'
...
The reason why this doesn't work for me, is that it would require writing a loop each time I want to get an array of parameters, which is relatively frequent.
What I have tried:
I have solved this by creating a parentObj.getVarArray(obj,string) and parentObj.setVarArray(obj,string) functions which use getfield() and setfield(). For example:
classdef ParentObj
methods
function varArray = getVarArray(obj, varString)
varArray = zeros(length(obj.myObjArray),1);
% Convert varString to cell array
fields = textscan(varString,'%s','Delimiter','.');
for i=1:length(obj.myObjArray)
varArray(i) = getfield(obj.myObjArray(i),fields{1}{:});
end
end
end
end
% Usage:
out = parentObj.getVarArray('myObj.myStruct.myProperty');
This works very well from a useability perspective, despite not using native syntax, but it is slow. I am performing these operations on very large data sets.
I have also tried overriding the subsasgn() and subsref() functions, but have found this difficult. I also question if these will offer a signficant performance improvement. It seems to significantly slow down performance even if I just pass them through the subsref function and use the builtin subsref.
What is the best way to maintain my object structure while greatly improving get/set performance?
  • Fully implement subsasgn and subsref? If so, how would I do this efficienctly?
  • Implement some sort of private data structure which is not visible to the user, but is much more efficient to access. Override get.Param and set.Param methods for this?

Accepted Answer

Matt J
Matt J on 20 Dec 2018
Edited: Matt J on 20 Dec 2018
Implement some sort of private data structure which is not visible to the user, but is much more efficient to access.
This. If you have a large amount of data, you need to store them sequentially in memory in a single object (i.e., not split across multiple objects and structs) in order to access them quickly.
Overloading subsref/subsasgn is just a tool to control how you want the indexing syntax to look. It has nothing to do with speed.
  2 Comments
Alex Luck
Alex Luck on 20 Dec 2018
What would you recommend this look like for maximizing speed?
What I have currently tested is creating a nested structure that mirrors the object structure names and values and this has achieved a 50% improvement on speed when using setfield() and getfield().
Additionally, will overriding set() and get() methods for my class accomplish the same thing for all properties as overriding set.Property() and get.Property() would for an individual property?
Matt J
Matt J on 20 Dec 2018
Edited: Matt J on 20 Dec 2018
What would you recommend this look like for maximizing speed?
It's hard to make recommendations based on the level of detail you've given us. One example though, is to take all the myProperty data and combine it all into one matrix. In other words, create the 'out' array in advance, in the constructor, and store it as a property parentObj.out so that you have immediate/fast access to it later. Then, you implement different data lookup methods appropriate to different situations and their speed requirements.
For example, for cases where speed isn't a high priority and you just want to do leisurely lookup, you could still use subsref/subsasgn to enable lookup syntax like
parentObj.myObjArray(i).myObj.myStruct.myProperty(j);
if that's what's most intuitive for you. The code for subsref would simply map (i,j) to the appropriate location in parentObj.out and extract from it appropriately. How slow/fast this lookup operation would be will depend on how complex the computation is when mapping from (i,j) to the corresponding coordinates in parentObj.out.
Additionally, will overriding set() and get() methods for my class accomplish the same thing for all properties as overriding set.Property() and get.Property() would for an individual property?
No, but I don't believe it's relevant to your question. set.Property() and get.Property() are not appropriate for customizing nested indexing syntax like the kind you want here. You need to use subsref and subsasgn for that.

Sign in to comment.

More Answers (1)

James Tursa
James Tursa on 20 Dec 2018
Whether this works or not depends on what is in the properties, but have you tried simple concatenation on the rhs?
[out] = [parentObj.myObjArray.myObj.myStruct.myProperty];
  1 Comment
Alex Luck
Alex Luck on 20 Dec 2018
That produces the following error: Expected one output from a curly brace or dot indexing expression, but there were N results.

Sign in to comment.

Categories

Find more on Customize Object Indexing in Help Center and File Exchange

Products


Release

R2018b

Community Treasure Hunt

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

Start Hunting!