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 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.




Published with MATLAB® 7.3

|

Comments

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