0

I have a struct array: a 1x10 struct array with fields: N, t, q, r, T, each of which is a vector of type double.
enter image description here

The 10 array entries each represent the outcome of a testing condition in an experiment. I would like to be able to make a function that takes two indices, index1 and index2, and modifies the constituent N, t, q, r vectors (T is a single number) so that they become length index1:index2. Something like

function sa = modifier(struct_array, index1, index2)
    sa = structfun(@(x) x(index1:index2), struct_array, 'UniformOutput', false)
    stuff
end

Now, where stuff is, I've tried using structfun and cellfun, see here except that those return a struct and a cell array, respectively, whereas I need to return a struct array.

The purpose of this is to be able to get certain sections of the experimental results, e.g. maybe the first five entries in each vector inside each cell correspond to the initial cycles of the experiment.

Please let me know if this is possible, and how I might go about it!

Community
  • 1
  • 1
call-in-co
  • 281
  • 2
  • 11

1 Answers1

1

You can try this:

From this question's answer, I figured out how to loop through struct fields. I modified the code to address your question by extracting a subsample from each field that goes through the for loop and then copy the desired subset of that data into a new struct array with identically named fields.

% Define indexes for extraction
fieldsToTrim = {'a' 'b'};
idx = 2:3; % Create index vector for extracting selected data range

% Define test struct to be read
teststruct.a = [1 2 3];
teststruct.b = [4 5 6];
teststruct.c = [7 8 9];

% Get names of struct fields
fields = fieldnames(teststruct);

% Loop through each field and extract the subset
for i = 1:numel(fields)
    if max(strcmp(fields{i},fieldsToTrim)) > 0
        % If current matches one of the fields selected for extraction
        % extract subset
        teststructResults.(fields{i}) = teststruct.(fields{i})(idx);
    else
        % Else, copy all contents on field to resulting struct
        teststructResults.(fields{i}) = teststruct.(fields{i});
    end
end

Finally, to turn this into a function, you can modify the above code to this:

function teststructResults =  extractSubsetFromStruct(teststruct,fieldsToTrim,idx1, idx2)
    % idx1 and idx2 are the start and end indicies of the desired range

    % fieldsToTrim is a string array of the field names you want
    % included in the trimming, all other fields will be fully copied

    % teststruct is your input structure which you are extracting the
    % subset from

    % teststructResults is the output containing identically named
    % struct fields to the input, but only containing data from the selected range

    idx = idx1:idx2; % Create index vector for extracting selected data range

    % Get names of struct fields
    fields = fieldnames(teststruct);

    % Loop through each field and extract the subset
    for i = 1:numel(fields) 
        if max(strcmp(fields{i},fieldsToTrim)) > 0
            % If current matches one of the fields selected for extraction
            % extract subset
            temp = teststruct.(fields{i});
            teststructResults.(fields{i}) = temp(idx);
        else
            % Else, copy all contents on field to resulting struct
            teststructResults.(fields{i}) = teststruct.(fields{i});
        end
    end
end

I successfully ran the function like this:

teststruct = 

    a: [1 2 3]
    b: [4 5 6]
    c: [7 8 9]

>> extractSubsetFromStruct(teststruct,{'a' 'b'},2,3)

ans = 

    a: [2 3]
    b: [5 6]
    c: [7 8 9]
Community
  • 1
  • 1
RTbecard
  • 868
  • 1
  • 8
  • 23
  • I'm getting this error: `Field reference for multiple structure elements that is followed by more reference blocks is an error.` – call-in-co Aug 05 '15 at 21:14
  • 1
    hmm.. give me a minute, I'll retest the code and repost! – RTbecard Aug 05 '15 at 21:16
  • K, updated, and I made a few changes to the function. – RTbecard Aug 05 '15 at 21:22
  • The problem I'm getting is that `teststructResults.(fields{i}) = teststruct.(fields{i})(idx)` will not evaluate. Once the i-th fieldname is selected, `teststruct.(fields{i})` is okay, because it returns all of the fields of that name in the struct, but it's not allowed to return the 2:4 elements *of each of those*. – call-in-co Aug 05 '15 at 21:30
  • Your most recent update that introduced an intermediate `temp` has done the trick for me. Thank you so very much, @James. – call-in-co Aug 05 '15 at 21:43
  • ah cool! I made the update, but I was hesitating to add a comment as I was confused as to how this error was coming up on your machine, but not mine. For curiosity's sake, what version of matlab are you using? I ran the previous version of the function fine on (2012a, Linux) – RTbecard Aug 05 '15 at 21:46
  • I'm running 2012b on Windows. – call-in-co Aug 05 '15 at 21:46