Working with Arrays of Structures
Though I have covered this topic somewhat in the past, it seems like a good time to refresh the information. There are recent posts on the MATLAB newsgroup relating to this topic such as this one.
Contents
Original Question
Suppose I have a structure array and want to find all the entries with a value of 4, without looping, something like [m,n] = find(f.h == 4).
f(1).h = [1 2 3 4]; f(2).h = [5 6 7 8]; try [m,n] = find(f.h == 4); end
Why can't I use the find statement directly? Let's take a look at the error message to understand.
lerr = lasterror; disp(lerr.message)
Error using ==> eq Too many input arguments.
Too many input arguments? What is f.h? For that matter, what exactly is f again?
f
f = 1x2 struct array with fields: h
f is a struct array, and f.h is a comma-separated list.
f.h
ans = 1 2 3 4 ans = 5 6 7 8
Alternatives
To turn this list into a MATLAB construct I can use, I'd normally either wrap it inside [] or {}. If I wrap f.h inside [], I lose the information about what is in the first element of f and what is in the second.
[f.h]
ans = 1 2 3 4 5 6 7 8
Wrapping f.h inside {}, I have a cell array to work with.
{f.h}
ans = [1x4 double] [1x4 double]
I still can't immediately use find or numeric functions on this array.
try [m,n] = find({f.h} == 4); end lerr = lasterror; disp(lerr.message)
Error using ==> evalin Undefined function or method 'eq' for input arguments of type 'cell'.
Solution
What I'd like is a way to work with my struct, without writing too much code, without looping, that is ideally a pattern I can reuse as my problem evolves. This is exactly what arrayfun was designed to help with. It works on each element of an array, and I need to just tell it what I want to operate on one element, as well as telling arrayfun what array to work on.
Let's first find the values in the struct array f equal to 4. Since I have 2 arrays embedded in f, and they may each have different numbers of outputs, I have to clearly state that the outputs need to go into a cell array.
[m,n] = arrayfun(@(x)find(x.h==4),f,'uniformoutput',false)
m = [1] [1x0 double] n = [4] [1x0 double]
This becomes even more obvious if I can another array, g that is even less "regular" than f.
g = f;
g(3).h = [1 2 17 4];
g(4).h = [1 3 17 5 9 17];
[mg,ng] = arrayfun(@(x)find(x.h==17),g,'uniformoutput',false)
mg = [1x0 double] [1x0 double] [1] [1x2 double] ng = [1x0 double] [1x0 double] [3] [1x2 double]
Some problems are more benign however and it would be wasteful to return results in a cell array and then have to unpack them into a numeric array, for example, the function max, which generally has a single value as the result.
[minval,idx] = arrayfun(@(x)max(x.h),f) [minval,idx] = arrayfun(@(x)max(x.h),g)
minval = 4 8 idx = 4 4 minval = 4 8 17 17 idx = 4 4 3 3
Related Topics
Here are some links to related blogs and MATLAB reference pages.
Your Thoughts
- Do you use struct arrays?
- If yes, do you use arrayfun, or do you use loops? Whichever your choice is, can you say more about why it's your choice?
- Do you avoid struct arrays all together and use something else? If so, what data representations do you use instead?
Let's see your feedback here.
- Category:
- Structures
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.