1

I have a struct array in Matlab as follows:

temp_links = struct('src',{},'dest',{}, 'type', {}, 'datarate', {});

the data in temp_links is as follows:

===============================
src    dest    type    datarate
================================
sw_1   sw_2    sw       23
sw_1   sw_2    sw       34
sw_1   sw_2    sw       2
sw_1   sw_2    sw       3
sw_1   sw_3    sw       5
sw_1   sw_3    sw       8
sw_1   sw_3    sw       9
sw_1   sw_3    sw       3
sw_1   sw_3    sw       23
sw_1   sw_3    sw       20
sw_2   dev1    dev      30
sw_2   dev1    dev      20
...
=============================

In the above case, I would like to sum the datarates for the same src and dest and get a new struct array as follows:

=============================
src    dest    type    datarate
================================
sw_1   sw_2    sw       62
sw_1   sw_3    sw       68
sw_1   dev1    dev      50
...
=============================

I am confused on how to achieve this. My thoughts were to have a switch case for each src field and then populate the dest. But I am pretty sure there is a simple way which hasn't hit me yet.

Could someone help me with this.

gnovice
  • 125,304
  • 15
  • 256
  • 359
smyslov
  • 1,279
  • 1
  • 8
  • 29

3 Answers3

4

One approach could be to identify the unique rows using unique and then use some logical indexing to combine their data rates.

For example:

% Sample Data
temp_links = struct('src',{'sw_1', 'sw_1', 'sw_1', 'sw_2', 'sw_2', 'sw_2'}, ...
                    'dest',{'sw_2', 'sw_2', 'sw_3', 'sw_1', 'dev_1', 'dev_1'}, ...
                    'type', {'sw', 'sw', 'sw', 'sw', 'dev', 'dev'}, ...
                    'datarate', {23, 34, 2, 5, 5, 5} ...
                    );

% Locate and index each unique source, destination, and type
[src_nodes, ~, src_idx] = unique({temp_links(:).src});
[dest_nodes, ~, dest_idx] = unique({temp_links(:).dest});
[types, ~, type_idx] = unique({temp_links(:).type});

% Combine the indices and use to locate and index unique rows
row_layout = [src_idx, dest_idx, type_idx];
[unique_rows, ~, row_idx] = unique(row_layout, 'rows');

% Initialize results table based on the unique rows
joined_links = struct('src', {src_nodes{unique_rows(:,1)}}, ...
                      'dest', {dest_nodes{unique_rows(:,2)}}, ...
                      'type', {types{unique_rows(:,3)}}, ...
                      'datarate', [] ...
                      );

% Sum data rates for identical rows
for ii = 1:size(unique_rows, 1)
    joined_links(ii).datarate = sum([temp_links(row_idx==ii).datarate]);
end

For our sample input structure:

 src       dest      type     datarate
______    _______    _____    ________

'sw_1'    'sw_2'     'sw'     23      
'sw_1'    'sw_2'     'sw'     34      
'sw_1'    'sw_3'     'sw'      2      
'sw_2'    'sw_1'     'sw'      5      
'sw_2'    'dev_1'    'dev'     5      
'sw_2'    'dev_1'    'dev'     5  

We recieve the following joined structure:

 src       dest      type     datarate
______    _______    _____    ________

'sw_1'    'sw_2'     'sw'     57      
'sw_1'    'sw_3'     'sw'      2      
'sw_2'    'dev_1'    'dev'    10      
'sw_2'    'sw_1'     'sw'      5 

Alternatively, if you want to use MATLAB's Table datatype you can more easily utilize findgroups and splitapply to achieve the same result.

Using the same temp_links struct from above:

temp_links = struct2table(temp_links);
groups = findgroups(temp_links.src, temp_links.dest, temp_links.type);
combined_datarate = splitapply(@sum, temp_links.datarate, groups);

[unique_groups, idx] = unique(groups);
joined_links = temp_links(idx, :);
joined_links.datarate = combined_datarate;

Which also returns:

 src       dest      type     datarate
______    _______    _____    ________

'sw_1'    'sw_2'     'sw'     57      
'sw_1'    'sw_3'     'sw'      2      
'sw_2'    'dev_1'    'dev'    10      
'sw_2'    'sw_1'     'sw'      5      
sco1
  • 12,154
  • 5
  • 26
  • 48
1

You can combine the first two fields 'src' and 'dest' into a string and use unique to create indices for 1) extracting unique sets (index1 below) and 2) summing the data rates with accumarray (index2 below):

% Sample data (from excaza's answer):
temp_links = struct('src',{'sw_1', 'sw_1', 'sw_1', 'sw_2', 'sw_2', 'sw_2'}, ...
                    'dest',{'sw_2', 'sw_2', 'sw_3', 'sw_1', 'dev_1', 'dev_1'}, ...
                    'type', {'sw', 'sw', 'sw', 'sw', 'dev', 'dev'}, ...
                    'datarate', {23, 34, 2, 5, 5, 5});

% Get indices for unique src/dest combinations:
[~, index1, index2] = unique([strvcat(temp_links.src) strvcat(temp_links.dest)], 'rows');
unique_links = temp_links(index1);      % Get subset of structure array
datarate = num2cell(accumarray(index2, [temp_links.datarate]));  % Sum datarates
[unique_links.datarate] = datarate{:};  % Add datarate sums to subarray
gnovice
  • 125,304
  • 15
  • 256
  • 359
-3

Create a new struct with the unique dest as you defined.
From here you have 2 options:

  1. Loop over all fields of the source struct and add them to the new struct.
  2. Use MATLAB's indexing.

The first one is faster.
The second one is much slower but the code might be more MATLAB Style.

Royi
  • 4,640
  • 6
  • 46
  • 64