Loren on the Art of MATLAB

Turn ideas into MATLAB

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 asthis 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 thefindstatement 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? Whatisf.h? For that matter, what exactly isfagain?

f
f = 1x2 struct array with fields: h

fis astructarray, andf.his 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 wrapf.hinside[], I lose the information about what is in the first element offand what is in the second.

[f.h]
ans = 1 2 3 4 5 6 7 8

Wrappingf.hinside{}, I have a cell array to work with.

{f.h}
ans = [1x4 double] [1x4 double]

I still can't immediately usefindor numeric functions on this array.

try[m,n] = find({f.h} == 4);endlerr = 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 whatarrayfunwas 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 tellingarrayfunwhat array to work on.

Let's first find the values in the struct arrayfequal to 4. Since I have 2 arrays embedded inf, 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,gthat is even less "regular" thanf.

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 functionmax, 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 usearrayfun, 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 feedbackhere.




Published with MATLAB® 7.3

|
  • print
  • send email

Comments

To leave a comment, please clickhereto sign in to your MathWorks Account or create a new one.