Modifying a structure array

Hi. I am working with a structure array, and I want to modify the structure based on a condition on the field entries.
For example,
Here is the input,
S(1).f1=[1:100] and S(2).f2=[2:101];
S(2).f1=[40:120] and S(2).f2=[60:140]
S(3).f1=...... and S(3).f2=.....
S(4).f1=.... and S(4).f2=.....
.
.
S(i).f1=.... and S(i).f2=....
Can anyone suggest me some smart way to do this.
Conditions on input Output
S(1).f1>=0 and S(1).f1<=50 then ------> S(1).f1=[1:50] and S(1).f2=[2:51]
S(1).f1>50 and S(1).f1<=100 then ------>S(2).f1=[51:100] and S(2).f2=[52:101]
.... so on
Now, the same process for original/input S(2).f1, S(3).f1 .... S(i).f1 to re-form the structure.
After, modification the final step is to delete S(i) if the size of S(i).f1 is < 5.

3 Comments

So when a split occurs the new entry should be put between the parent position and the position after it? Under that assumption I'll edit my answer.
And where are those condition values coming from?
Hi Rik. The order doesn't matter, I just want them them to form a new column. It is from some biological process and I have to break the structure for a span of 50 units of a given field.

Sign in to comment.

 Accepted Answer

Bruno Luong
Bruno Luong on 12 Aug 2019
Edited: Bruno Luong on 12 Aug 2019
S=struct;
S(1).f1=5*[2,3,4,5,6,7,8,10,14,16,18,20];
S(1).f2=5*[3,6,9,12,15,18,21,24,27,30,33,36];
S(2).f1=40:120;S(2).f2=60:140;
S(3).f1=20:100;S(3).f2=40:120;
filtfun = @(s) s.f1>=0 & s.f1<=50; % adapt to your need
b = arrayfun(filtfun, S, 'unif', 0);
Sfilter = arrayfun(@(s,b) structfun(@(a) a(b{1}), s, 'unif', 0), S, b); % your reasult
I let you do the deletion step.

12 Comments

Thanks for the reply Bruno Luong. What is the smart way to implement the same if there are 30 specific named fields? The condition is only on the elements of one field.
Bruno Luong
Bruno Luong on 12 Aug 2019
Edited: Bruno Luong on 12 Aug 2019
The question is more about the interfacing design: how you intend for user to enter conditions on 30 fields?
If you can tell us it's always a lower/upper bound and you put them on array and associate each element to the field, then we can do something. But you have to specify your way to input the filter on 30 fields.
SS
SS on 12 Aug 2019
Edited: SS on 12 Aug 2019
For each S(i), the length of the field arrays is same throughout except 5 fields. The length of these 5 fields is 1 less than the other 25 field arrays. The last element in the these fields can be conisder as zero or empty, it doesn't matter.
The condition is only on one field (say field f1) which includes both lower bound and upper bound. For example, S.f1>=50 & S.f1<=100.
I want to modify the structure array which includes the elements based on the given condition. I want the elements in S.f1 which satisfies the given condition and other fields to have the elements of corresponding indices of S.f1.
"The condition is only on one field (say field f1) The condition is only on one field (say field f1) For example, S.f1>=50 & S.f1<=100."
Alright, then simply change the first line of my code to
filtfun = @(s) s.f1>=50 & s.f1<=100; % adapt to your need
Wonder why you make a comment, I never use f1, f2, f3 anywehere in my code (beside f1 in the condition of course) it works assuming all the fields having the same length, that's all. You can have 300 fields it's still working. Have you tried it before posting your comment?
I let you deal with the exception of one less element on 5 fields (that's messy condition, and bad data structure design), you better fill them with trailing 0 or NaN, whatever suitable for you, to make all the fields have the same length.
Could you please, help me with the deletion step in this code. I tried but, didn't succeed.
Add this as the last statement of my code:
Sfilter(cellfun(@sum,b)<5) = []
Thank you so much.
Hi again. I have tried to use the above code and unfortunately, it gives the follwoing error.
The logical indices contain a true value outside of the array bounds.
Error in @(a)a(b{1})
Error in @(s,b)structfun(@(a)a(b{1}),s,'unif',0)
How can, I fix this?
What data are you using with this? And what is the full code you were using? Try to make a MWE so we can run your code without any other dependencies and can reproduce your issue.
SS
SS on 26 Aug 2019
Edited: SS on 26 Aug 2019
Hi. I am unable to upload the S.dat file because, of its large size. I am using the field "growth" to re-arrange my structure. Here are some entries to give an idea about the type of data.
S(1).growth=[69.0899,69.1163,69.1295,69.1212,69.0978,69.0671];
S(2).growth=[68.6689379657871 68.6012576662520 68.5432527036940 68.5183488830736 68.4623425084315 68.4032211916516 68.4089831038520 68.4303882075090 68.4787272982599 68.4441422394964 68.3360147869897 68.2795868644623];
S(3).growth=[40.6236,40.2163,39.8215,39.4620,39.1736,38.9691];
S(4).growth=[65.3854,64.8621,64.3253,63.7556,63.1388];
...... so on.
load('S');
filtfun = @(s) s.growth>=0 & s.growth<=50;
b = arrayfun(filtfun, S, 'unif', 0);
Sfilter = arrayfun(@(s,b) structfun(@(a) a(b{1}), s, 'unif', 0), S, b);
Sfilter(cellfun(@sum,b)<5) = []
S1=Sfilter;
After clearing the above variables
load('S');
filtfun = @(s) s.growth>50 & s.growth<=100;
b = arrayfun(filtfun, S, 'unif', 0);
Sfilter = arrayfun(@(s,b) structfun(@(a) a(b{1}), s, 'unif', 0), S, b);
Sfilter(cellfun(@sum,b)<5) = []
S2=Sfilter;
Neither code section produces the error you indicate. You should try to find a data line that causes this error. That is one of the hallmarks of an MWE: the smallest section of data and code that produces the error.
Often when trying to create an MWE you already find the mistake on your own. I have sometimes started writing my own question, when I found the mistake when creating an MWE for my post.
Bruno Luong
Bruno Luong on 26 Aug 2019
Edited: Bruno Luong on 26 Aug 2019
SS: "Hi again. I have tried to use the above code and unfortunately, it gives the follwoing error."
This error is expected to me because you wrote:
"For each S(i), the length of the field arrays is same throughout except 5 fields. The length of these 5 fields is 1 less than the other 25 field arrays. The last element in the these fields can be conisder as zero or empty, it doesn't matter."
Actually it does MATTER, contrary to what you wrote.
And I have warned you long ago.
"I let you deal with the exception of one less element on 5 fields (that's messy condition, and bad data structure design), you better fill them with trailing 0 or NaN, whatever suitable for you, to make all the fields have the same length."

Sign in to comment.

More Answers (1)

Rik
Rik on 11 Aug 2019
Edited: Rik on 11 Aug 2019
Since you don't provide any indication of how you want this to work for struct array input, you'll have to modify this code yourself.
S=struct;
S(1).f1=[2,3,4,5,6,7,8,10,14,16,18,20];
S(1).f2=[3,6,9,12,15,18,21,24,27,30,33,36];
L=S(1).f1<=10;
if sum(L)>=5
S(2).f1=S(1).f1(L);
S(2).f2=S(1).f2(L);
end
S(1).f1(L)=[];S(1).f2(L)=[];
Edit:
%create input struct
S=struct;
S(1).f1=5*[2,3,4,5,6,7,8,10,14,16,18,20];
S(1).f2=5*[3,6,9,12,15,18,21,24,27,30,33,36];
S(2).f1=40:120;S(2).f2=60:140;
S(3).f1=20:100;S(3).f2=40:120;
%create the cell array that will hold the struct elements
c=cell(2,numel(S));
for n=1:numel(S)
c{1,n}=S(n);
L=S(n).f1<=50;
if sum(L)>=5
c{2,n}.f1=S(n).f1(L);
c{2,n}.f2=S(n).f2(L);
end
c{1,n}.f1(L)=[];c{1,n}.f2(L)=[];
end
%reshape back to a struct
S=[c{:}];

4 Comments

SS
SS on 12 Aug 2019
Edited: SS on 12 Aug 2019
HI Rik. This is not working for conditions like >= and <=. Example, S.f1>=50 && S.f1<=100.
Also, it might be useful for me later. What is the smart way if there are 30 fields instead of 2.
That is not working because you use && instead of &. The single operator should be used for arrays, the double operator for scalars.
For numbered fields you could use a loop like this:
for n=1:5
S.(sprintf('f%d',n)) = rand;
end
SS
SS on 12 Aug 2019
Edited: SS on 12 Aug 2019
Thank you. What should be the approach if these are not numbered fields and some specific names?
The .() syntax works for char array inputs (and scalar strings).

Sign in to comment.

Categories

Asked:

SS
on 11 Aug 2019

Edited:

on 26 Aug 2019

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!