MATLAB: Copying variables from table to struct based on certain criteria - matlab

I have a table
column1data = [11; 22; 33];
column2data = [44; 55; 66];
column3data = [77; 88; 99];
rows = {'name1', 'name2', 'name3'};
T = table(column1data, column2data, column3data);
T.Properties.RowNames = rows
column1data column2data column3data
name1 11 44 77
name2 22 55 88
name3 33 66 99
and a struct array
S(1).rownamefield = 'name3';
S(2).rownamefield = 'name1';
S(3).rownamefield = 'name2';
S(1).columnnumberfield = 1;
S(2).columnnumberfield = 3;
S(3).columnnumberfield = 2;
S(1).field3 = [];
S(2).field3 = [];
S(3).field3 = [];
rownamefield columnnumberfield field3
1 'name3' 1 []
2 'name1' 3 []
3 'name2' 2 []
The struct array S contains criteria needed to pick the variable from table T. Once the variable is picked, it has to be copied from table T to an empty field in struct S.
S(1).rownamefield contains the name of the row in table T where the target variable resides. S(1).columnnumberfield contains the number of the column in table T with the target variable. So S(1).rownamefield plus S(1).columnnumberfield are practically the coordinates of the target variable in table T. I need to copy the target variable from table T to field3 in the struct array: S(1).field3. This has to be done for all structs so it might need to be in a for loop, but I am not sure.
The output should look like this:
rownamefield columnnumberfield field3
1 'name3' 1 33
2 'name1' 3 77
3 'name2' 2 55
I have no idea how to approach this task. This is, of course, a simplified version of the problem. My real data table is 200x200 and the struct array has over 2000 structs. I will greatly appreciate any help with this.

You could do something like the following.
First convert the rownamefield and columnnumberfield fields to cells and arrays to use as indices for the table.
rows = {S.rownamefield};
cols = [S.columnnumberfield];
subtable = T(rows, cols);
This gives you a square table which you can then convert to a cell and take the diagonal elements which are the ones you care about.
values = table2cell(subtable);
values = values(logical(eye(numel(rows))));
Then this gives a cell array of the values corresponding to the entries in S. We can then assign them
[S.field3] = deal(values{:});
disp([S.field3])
33 77 55
This would be much easier if table had an equivalent to sub2ind.

% Extract table data and linearly index it
tdata = T{:,:};
[~,row] = ismember({S.rownamefield}, T.Properties.RowNames);
col = [S.columnnumberfield];
pos = sub2ind(size(tdata),rowpos, col);
val = tdata(pos);
% Assign to struct
for ii = 1:numel(S)
S(ii).field3 = val(ii);
end
Instead of the for-loop, you can use Suever's solution with the deal() to assign values in one go (have to num2cell(val) first). Whatever is faster and more intuitive.

Related

count number of elements with a specific value in a field of a structure in Matlab

I have a structure myS with several fields, including myField, which in turns includes several other fields such as BB. I need to count how many time *'R_value' appears in BB.
I have tried:
sum(myS.myField.BB = 'R_value')
and this:
count = 0;
for i = 1:numel(myS.myField)
number_of_element = numel(myS.myField(i).BB)=='R_value'
count = count+number_of_element;
end
but it doesn't work. Any suggestion?
If you are just checking if BB is that literal string, then your loop is just:
count = 0;
for i = 1:numel(myS.myField)
count = count+strcmp(myS.myField(i).BB,'R_value')
end
numel counts how many elements are. Zero is an element. so is False. Just sum the array.
count = 0;
for i = 1:numel(myS.myField)
number_of_element = sum(myS.myField(i).BB==R_value)
count = count+number_of_element;
end
Also note you had the parenthesis wrong, so you where counting how many BB where in total, then comparing that number to R_value. I am assuming R_value is a number.
e.g.:
myS.myField(1).BB=[1 2 3 4 1 1 1]
myS.myField(2).BB=[4 5 65 1]
R_value=1

How to insert a structure within a structure

I have a 1x1 structure called imu_data.txyzrxyz1. It has one field called txyzrxyz1 and the value is 4877x7 double. I just want to "copy and paste" row 62 into row 63 (double up that row) so that the structure now becomes a 4878x7 structure. I've tried the following, with other versions without success:
extra_63 = imu_data.txyzrxyz1(63,:);
imu_data2.txyzrxyz1 = [{imu_data.txyzrxyz1(1:62,:) extra_63 imu_data.txyzrxyz1(63:end,:)}]
Thanks
You can index the row to duplicate twice while matrix indexing:
row_to_duplicate = 63;
yourdata = rand(100,10);
yourstruct.data = yourdata;
yourstruct.data = yourstruct.data([1:row_to_duplicate, row_to_duplicate:end],:)
So in case of 63, 1:row_to_duplicate will create a column vector from 1:63, and row_to_duplicate:end will create a column vector from 63:100 in this example. When combining these, 63 will occur twice, hence that row is duplicated.
You were almost there, you only had to get rid of the {}'s and put the data in the right orientation by using ; instead of a space between matrix entries to vertically concatenate instead of horizontally:
extra_63 = imu_data.txyzrxyz1(63,:);
imu_data2.txyzrxyz1 = [imu_data.txyzrxyz1(1:62,:); extra_63; imu_data.txyzrxyz1(63:end,:)]

Merging to dataset together according to key

I have two datasets stored in a cell array and a double array, respectively. The design of the two arrays is:
Array 1 (name: res) (double) is composed of two columns; a unique id column and a data column.
Array 2 (name: config) (cell array) contains 3 column cells, each with a string inside. The last cell in the array contains a id double integer matching the id's in Array 1. The double integer in the cell array is converted to a double when necessary.
I want to merge the two datasets in order to have the 3 cells in the cell array AND the result column in Array 1 in one common cell array. How do I do this?
I have the following code. The code does not return the correct order of the results.
function resMat = buildResultMatrix(res, config)
resMat = {};
count = 1;
count_max = size(res,1)/130;
for i = 1 : size(res,1)
for j = 1 : size(res,1)
if isequal(res(i),str2double(config{j,3}))
if i == 1
resMat(end+1,:) = {config{j,:} res(j,2:end)};
else
if count == 1
resMat(end+1,:) = {config{j,:} res(j,2:end)};
elseif count == count_max
resMat(end+1,:) = {config{j,:} res(j,2:end)};
else
resMat(end+1,:) = {config{j,:} res(j,2:end)};
end
count = count + 1;
end
end
end
count = 1;
end
end
First convert the id in config to numbers:
config(:,3) = num2cell(str2double(config(:,3)));
Then run this:
res = sortrows(res,1);
config(:,4) = num2cell(res(cell2mat(config(:,3)),2))
this will put the data from res in the 4th column in config in the row with the same id.

Remove rows from a matrix

I have the array "A" with values:
101 101
0 0
61.6320000000000 0.725754779522671
73.7000000000000 0.830301150185882
78.2800000000000 0.490917508345341
81.2640000000000 0.602561200211232
82.6880000000000 0.435568593909153
And I wish to remove this first row and retain the shape of the array (2 columns), thus creating the array
0 0
61.6320000000000 0.725754779522671
73.7000000000000 0.830301150185882
78.2800000000000 0.490917508345341
81.2640000000000 0.602561200211232
82.6880000000000 0.435568593909153
I have used A = A(A~=101); , which removes the values as required - however it packs the array down to one column.
The best way is:
A = A(2:end, :)
But you can also do
A(1,:) = []
however it is slightly less efficient (see Deleting matrix elements by = [] vs reassigning matrix)
If you are looking to delete rows that equal a certain number try
A = A(A(:,1)~=101,:)
Use all or any if you want to delete row if either all or any column equals your value:
A = A(all(A~=101,2),:)

How to we convert a cell array which is in a struct array into a table

I have a structured array (1*1502) named summary in which there is a cell array with field names results that has the following data:
[1,114,3,170686,1990;2,74,13,5668167,1997]
[1,91,1,96400,2011;2,108,1,1218510,2012]
[1,17314,3,951029,1998;2,62,1,193243,2004]
Each data belongs to one field
How can I put all single data into one field in a table?
summary(1).results gives me these as result which I want to store in a table
ans =
1 114 3 170686 1990
2 74 13 5668167 1997
Use the function cell2table
Example:
T = cell2table(C)
Example with variable names:
T = cell2table(C,...
'VariableNames',{'Age' 'FavoriteFood' 'Calories' 'NutritionGrade'})