1

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.

Suever
  • 64,497
  • 14
  • 82
  • 101
Arthur Tarasov
  • 3,517
  • 9
  • 45
  • 57
  • Do you have to stick with the structure? Are you deciding the how to store this info. I personally never use arrays of structure, such a pain to deal with. – Oleg Feb 06 '16 at 14:19
  • I only figured out how to store data in structures and tables. I have a lot of data sets so I put them into nested structures. I can't really put a table within a table (or can I?) so I have to use a structure on some level. I found it easier to work with nested structures than with tables within structures. Perhaps there is another way to tie it all together, but I am not aware of it. – Arthur Tarasov Feb 07 '16 at 03:30
  • Your data looks scalar, so I do not see the need for a structure instead of a table (probably your real data is more complex) – Oleg Feb 07 '16 at 12:22

2 Answers2

2

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.

Suever
  • 64,497
  • 14
  • 82
  • 101
  • I like the diagonal intuition, but it is also its weakness due to scalability. You also gave me a good idea for my [extended `table()` class](https://github.com/okomarov/tableutils), i.e. to implement a `sub2ind()` – Oleg Feb 06 '16 at 14:27
  • @Oleg Definitely could be an issue with increasing size. – Suever Feb 06 '16 at 14:28
  • @Suever Thank you! Works great – Arthur Tarasov Feb 07 '16 at 03:25
1
% 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.

Oleg
  • 10,406
  • 3
  • 29
  • 57