I have an array of structures where each struct contains 3 fields. The array is shown below in the image. The three fields are 'Measured_Signal_lvl', 'BiD', and 'SiD'. I want to bin the data by BiD and SiD. The BiD field can take on values from 0-7, and SiD can be [1,4,10,18] only. I want to put all the same BiDs in its respective group with their corresponding SiDs. So I expect to have a separate group for each BiD and there should be 8.
So far, what I have done is convert the array to a MATLAB table. Then I use the 'ismember' function to group all of the BiDs and store them in a separate table. Then, I repeat the same process, but on the already grouped BiD tables to get all of the SiDs within each BiD table. As you can see this approach is not too efficient and the code, as posted below is very repetitive. I would like to utilize a more efficient approach both in code and architecture.
Snapshot of the structure array:
Code I currently have:
% Find all the BiD == 0
bId_0 = st(ismember(st.BiD,0),:);
% Find all the BiD == 1
bId_1 = st(ismember(st.BiD,1),:);
% Find all the BiD == 2
bId_2 = st(ismember(st.BiD,2),:);
% Find all the BiD == 3
bId_3 = st(ismember(st.BiD,3),:);
% Find all the BiD == 4
bId_4 = st(ismember(st.BiD,4),:);
% Find all the BiD == 5
bId_5 = st(ismember(st.BiD,5),:);
% Find all the BiD == 6
bId_6 = st(ismember(st.BiD,6),:);
% Find all the BiD == 7
bId_7 = st(ismember(st.BiD,7),:);
% % Drill Further to find the SIDs per BIDs
% % all BId 0s, SiD 1,4,10,18
bId_0_sId_1 = bId_0(ismember(bId_0.SiD,1),:);
bId_0_sId_4 = bId_0(ismember(bId_0.SiD,4),:);
bId_0_sId_10 = bId_0(ismember(bId_0.SiD,10),:);
bId_0_sId_18 = bId_0(ismember(bId_0.SiD,18),:);
% all BId 1s, SiD 1,4,10,18
bId_1_sId_1 = bId_1(ismember(bId_1.SiD,1),:);
bId_1_sId_4 = bId_1(ismember(bId_1.SiD,4),:);
bId_1_sId_10 = bId_1(ismember(bId_1.SiD,10),:);
bId_1_sId_18 = bId_1(ismember(bId_1.SiD,18),:);
% all BiD 2s, SiD 1,4,10,18
bId_2_sId_1 = bId_2(ismember(bId_2.SiD,1),:);
bId_2_sId_4 = bId_2(ismember(bId_2.SiD,4),:);
bId_2_sId_10 = bId_2(ismember(bId_2.SiD,10),:);
bId_2_sId_18 = bId_2(ismember(bId_2.SiD,18),:);
% all BiD 3s, SiD 1,4,10,18
bId_3_sId_1 = bId_3(ismember(bId_3.SiD,1),:);
bId_3_sId_4 = bId_3(ismember(bId_3.SiD,4),:);
bId_3_sId_10 = bId_3(ismember(bId_3.SiD,10),:);
bId_3_sId_18 = bId_3(ismember(bId_3.SiD,18),:);
% all BiD 4s, SiD 1,4,10,18
bId_4_sId_1 = bId_4(ismember(bId_4.SiD,1),:);
bId_4_sId_4 = bId_4(ismember(bId_4.SiD,4),:);
bId_4_sId_10 = bId_4(ismember(bId_4.SiD,10),:);
bId_4_sId_18 = bId_4(ismember(bId_4.SiD,18),:);
% all BiD 5s, SiD 1,4,10,18
bId_5_sId_1 = bId_5(ismember(bId_5.SiD,1),:);
bId_5_sId_4 = bId_5(ismember(bId_5.SiD,4),:);
bId_5_sId_10 = bId_5(ismember(bId_5.SiD,10),:);
bId_5_sId_18 = bId_5(ismember(bId_5.SiD,18),:);
% all BiD 6s, SiD 1,4,10,18
bId_6_sId_1 = bId_6(ismember(bId_6.SiD,1),:);
bId_6_sId_4 = bId_6(ismember(bId_6.SiD,4),:);
bId_6_sId_10 = bId_6(ismember(bId_6.SiD,10),:);
bId_6_sId_18 = bId_6(ismember(bId_6.SiD,18),:);
% all BiD 7s, SiD 1,4,10,18
bId_7_sId_1 = bId_7(ismember(bId_7.SiD,1),:);
bId_7_sId_4 = bId_7(ismember(bId_7.SiD,4),:);
bId_7_sId_10 = bId_7(ismember(bId_7.SiD,10),:);
bId_7_sId_18 = bId_7(ismember(bId_7.SiD,18),:);
You should generally try to avoid dynamic variable names like bId_2_sId_1
, they quickly become a nightmare to maintain, and it becomes hard to do simple things like loop over similar variables. One approach would be to use a struct:
% Convert struct to table since they're easier to extract rows from
light_data = struct2table( light_data, 'AsArray', true );
% Set up output structure
light_data_grouped = struct();
% Loop over each unique pair of BiD and SiD
[grp, uBiD, uSiD] = findgroups(light_data.BiD, light_data.SiD);
for g = 1:max(grp)
% Generate the struct field names
BiDstr = sprintf('BiD_%d', uBiD(g));
SiDstr = sprintf('SiD_%d', uSiD(g));
% Make sure the BiD field exists
if ~isfield( light_data_grouped, BiDstr )
light_data_grouped.(BiDstr) = struct();
end
% Assign table subset into the SiD sub-field
light_data_grouped.(BiDstr).(SiDstr) = light_data(g == grp, 'Measured_Signal');
end
Using the same example input shown in your question, this gives the following outputs:
So you can easily access the elements you want using something like light_data_grouped.BiD_0.SiD_1;
, or as in the above code you can loop over the groups or BiD and SiD values independently.
If you want the fields to exist even if there are no corresponding rows in the data table then you can loop over all values of both BiD and SiD and simply extract the table subset, which could be empty. The approach is similar and we still output a struct:
% Set up output structure
light_data_grouped = struct();
% Loop over each unique pair of BiD and SiD
uBiD = 0:7;
uSiD = [1,4,10,18];
for BiD = uBiD
BiDstr = sprintf('BiD_%d', BiD);
if ~isfield( light_data_grouped, BiDstr )
light_data_grouped.(BiDstr) = struct();
end
% Get rows with this BiD
idx_BiD = light_data.BiD == BiD;
for SiD = uSiD
SiDstr = sprintf('SiD_%d', SiD);
% Get rows with this SiD
idx_SiD = light_data.SiD == SiD;
% Get subset for BiD and SiD combo (could be empty)
light_data_grouped.(BiDstr).(SiDstr) = light_data(idx_BiD & idx_SiD, 'Measured_Signal');
end
end
Output: