0

I am trying to take the averages of a pretty large set of data, so i have created a function to do exactly that. The data is stored in some struct1.struct2.data(:,column) there are 4 struct1 and each of these have between 20 and 30 sub-struct2 the data that I want to average is always stored in column 7 and I want to output the average of each struct2.data(:,column) into a 2xN array/double (column 1 of this output is a reference to each sub-struct2 column 2 is the average)

The omly problem is, I can't find a way (lots and lots of reading) to point at each structure properly. I am using a string to refer to the structures, but I get error Attempt to reference field of non-structure array. So clearly it doesn't like this. Here is what I used. (excuse the inelegence)

function [avrg] = Takemean(prefix,numslits)
% place holder arrays
avs = [];
slits = [];
% iterate over the sub-struct (struct2)
for currslit=1:numslits
    dataname = sprintf('%s_slit_%02d',prefix,currslit);
    % slap the average and slit ID on the end
    avs(end+1) = mean(prefix.dataname.data(:,7));
    slits(end+1) = currslit;
end
% transpose the arrays
avs = avs';
slits = slits';
avrg = cat(2,slits,avs); % slap them together

It falls over at this line avs(end+1) = mean(prefix.dataname.data,7); because as you can see, prefix and dataname are strings. So, after hunting around I tried making these strings variables with genvarname() still no luck!

I have spent hours on what should have been 5min of coding. :'(

Edit: Oh prefix is a string e.g. 'Hs' and the structure of the structures (lol) is e.g. Hs.Hs_slit_XX.data() where XX is e.g. 01,02,...27

Edit: If I just run mean(Hs.Hs_slit_01.data(:,7)) it works fine... but then I cant iterate over all of the _slit_XX

6
  • When you say "there are 4 struct1 and each of these have between 20 and 30 sub-struct2", are you talking about arrays of structures, or separate fields with different names? Commented Sep 17, 2013 at 12:00
  • I am not sure. Basically going by the added example Hs is a 1x1 struct but contains Hs_slit_XX - each Hs_slit_XX contains a 23x8 double called data and 23x6 cell called text data Commented Sep 17, 2013 at 12:04
  • Why would you pass the name of the structure instead of the structure itself in the first place? Commented Sep 17, 2013 at 12:05
  • Because I need to be able to iterate over all of the like-named substructures... Commented Sep 17, 2013 at 12:07
  • 1
    Yeah. So it needs to be XX.XX_slit_YY.data(:,7) Commented Sep 17, 2013 at 12:15

2 Answers 2

2

If you simply want to iterate over the fields with the name pattern <something>_slit_<something>, you need neither the prefix string nor numslits for this. Pass the actual structure to your function, extract the desired fields and then itereate them:

function avrg = Takemean(s)

    %// Extract only the "_slit_" fields
    names = fieldnames(s);
    names = names(~cellfun('isempty', strfind(names, '_slit_')));

    %// Iterate over fields and calculate means
    avrg = zeros(numel(names), 2);
    for k = 1:numel(names)
        avrg(k, :) = [k, mean(s.(names{k}).data(:, 7))];
    end

This method uses dynamic field referencing to access fields in structs using strings.

Sign up to request clarification or add additional context in comments.

8 Comments

Didn't check performance, but a simpler way to make sure the names contain _slit_ would be names = names(strmatch('_slit_',names)). --- If you only want to use existing names (and I think this is the case) than this method is definately preferred over the string construction.
This looks promising (and quicker) I will give it a shot and update you.
YES!!!! You sir, are a legend! - and yes it is ~ 30% quicker ( took about 1sec rather than ~3sec) - Thank you!!! Have a cyber beer on me
@DennisJaheruddin actually I've replaced regexp with strfind, but I forgot to update the answer. Thanks for the suggestion.
I would go one further. Instead of storing your data across a bunch of sequential field names, use a cell array as a field. So, for example, hs.slit{1}. And avrg(k,:) = [k, mean(s.slit{k}.data(:,7)];
|
0

First of all, think twice before you use string construction to access variables.

If you really really need it, here is how it can be used:

a.b=123;
s1 = 'a';
s2 = 'b';
eval([s1 '.' s2])

In your case probably something like:

Hs.Hs_slit_01.data= rand(3,7);
avs = [];

dataname = 'Hs_slit_01';
prefix = 'Hs';

eval(['avs(end+1) = mean(' prefix '.' dataname '.data(:,7))'])

6 Comments

I know no other way to iterate over the names in matlab :( cool I will try that
It may work, but for large arrays that would be tremendously slow.
I tried avs(end+1) = mean(eval([prefix '.' dataname '.data(:,7)'])); but it gave an error Undefined variable "Hs" or class "Hs.Hs_slit_01.data".
@FriskyGrub That is not very strange, in your example the only inputs you give to the function are prefix and numslits. You can find this kind of stuff by using dbstop if error.
@DennisJaheruddin I tried eval('avs(end+1) = mean(' prefix '.' dataname '.data(:,7))') but I just get Unexpected MATLAB expression haha
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.