Loren on the Art of MATLAB

Turn ideas into MATLAB

Working with Arrays of Structures 30

Posted by Loren Shure,

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.


Get the MATLAB code

Published with MATLAB® 7.3

44 views (last 30 days)  | |

Comments

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