Maximum value of fields of nested structure - matlab

I have following structure:
S.s1.val = 1;
S.s2.val= 5;
S.s3.val= 4;
...
S.s10.value = 3;
How can I find max value of all val fields without using loops. And what is general solution to apply functions to all nested structure fields?

There is no general solution, but one way to think of is structfun to collect the data you want to process to an array.
maxval = max( structfun(#(x) x.val, S) )
Internally structfun works serially like a loop, so if you're really into speed, don't use structs (or cell arrays).

Related

Fastest type to use for comparing hashes in matlab

I have a table in Matlab with some columns representing 128 bit hashes.
I would like to match rows, to one or more rows, based on these hashes.
Currently, the hashes are represented as hexadecimal strings, and compared with strcmp(). Still, it takes many seconds to process the table.
What is the fastest way to compare two hashes in matlab?
I have tried turning them into categorical variables, but that is much slower. Matlab as far as I know does not have a 128 bit numerical type. nominal and ordinal types are deprecated.
Are there any others that could work?
The code below is analogous to what I am doing:
nodetype = { 'type1'; 'type2'; 'type1'; 'type2' };
hash = {'d285e87940fb9383ec5e983041f8d7a6'; 'd285e87940fb9383ec5e983041f8d7a6'; 'ec9add3cf0f67f443d5820708adc0485'; '5dbdfa232b5b61c8b1e8c698a64e1cc9' };
entries = table(categorical(nodetype),hash,'VariableNames',{'type','hash'});
%nodes to match. filter by type or some other way so rows don't match to
%themselves.
A = entries(entries.type=='type1',:);
B = entries(entries.type=='type2',:);
%pick a node/row with a hash to find all counterparts of
row_to_match_in_A = A(1,:);
matching_rows_in_B = B(strcmp(B.hash,row_to_match_in_A.hash),:);
% do stuff with matching rows...
disp(matching_rows_in_B);
The hash strings are faithful representations of what I am using, but they are not necessarily read or stored as strings in the original source. They are just converted for this purpose because its the fastest way to do the comparison.
Optimization is nice, if you need it. Try it out yourself and measure the performance gain for relevant test cases.
Some suggestions:
Sorted arrays are easier/faster to search
Matlab's default numbers are double, but you can also construct integers. Why not use 2 uint64's instead of the 128bit column? First search for the upper 64bit, then for the lower; or even better: use ismember with the row option and put your hashes in rows:
A = uint64([0 0;
0 1;
1 0;
1 1;
2 0;
2 1]);
srch = uint64([1 1;
0 1]);
[ismatch, loc] = ismember(srch, A, 'rows')
> loc =
4
2
Look into the compare functions you use (eg edit ismember) and strip out unnecessary operations (eg sort) and safety checks that you know in advance won't pose a problem. Like this solution does. Or if you intend do call a search function multiple times, sort in advance and skip the check/sort in the search function later on.

Indexing over all values in nested struct

I have a nested struct which contains values and is defined as:
mystruct.level1.a = 1;
mystruct.level1.b = 2;
mystruct.level2.a = 8;
mystruct.level2.b = 9;
I want to perform operations on the elements in level1 and level2. What I want to do is access the values in level1 and level2, put them in a vector, without referencing the nested field names.
E.g. I'd like to do something like:
level1_vector = [mystruct.level1]
Which I would like to output:
level1_vector = [1 2]
How can I do that?
Use the combination of two functions below:
cell2mat(struct2cell(mystruct.level1))
There's a structfun to do just that. It will return another struct, with the same names. So for your case:
con_struct = structfun (#(x) [x.a x.b], mystruct, "UniformOutput", false);
Now, con_struct will have the same fields as mystruct, but instead of a struct, each of them is an array with the values you wanted. You can feed each of arrays again to whatever function you want
structfun (#foo, con_struct)

assigning values to a field of an structure array in MATLAB

I want to replace the value of the fields in a structure array. For example, I want to replace all 1's with 3's in the following construction.
a(1).b = 1;
a(2).b = 2;
a(3).b = 1;
a([a.b] == 1).b = 3; % This doesn't work and spits out:
% "Insufficient outputs from right hand side to satisfy comma separated
% list expansion on left hand side. Missing [] are the most likely cause."
Is there an easy syntax for this? I want to avoid ugly for loops for such simple operation.
Credits go to #Slayton, but you actually can do the same thing for assigning values too, using deal:
[a([a.b]==1).b]=deal(3)
So breakdown:
[a.b]
retrieves all b fields of the array a and puts this comma-separated-list in an array.
a([a.b]==1)
uses logical indexing to index only the elements of a that satisfy the constraint. Subsequently the full command above assigns the value 3 to all elements of the resulting comma-separated-list according to this.
You can retrieve that the value of a field for each struct in an array using cell notation.
bVals = {a.b};
bVals = cell2mat( bVals );
AFAIK, you can't do the same thing for inserting values into an array of structs. You'll have to use a loop.

MATLAB -> struct.field(1:end).field?

Is there a way that I get all the structure subsubfield values of a subfield in one line ? Something like this :
struct.field(1:end).field
If I understand your question aright, you want to collect all the fields of the second-level structure, with the name 'field', into a single output array. It doesn't quite meet your request for a one-liner, but you can do it like this:
a.field1.a = 1;
a.field1.b = 2;
a.field2.a = 3;
a.field2.b = 4;
result = [];
for x = fieldnames(a)'
result = horzcat(result, a.(x{:}).a);
end
The ending value of result is [1 3]
Simple Structure Example
aStruct.subField = struct('subSubField', {1;2;3;4})
So that
aStruct.subField(1).subSubField == 1
aStruct.subField(1).subSubField == 2
Etc. Then the values of the leaf nodes can be obtained via a one-liner as
valueLeafs = [aStruct.subField.subSubField];
Which can be checked via assert(all(valueLeafs == [1,2,3,4])).
Non-Scalar Structure Example
The above one-liner also works when the leaf node values are non-scalar such that they can be horizontally concatenated. For example
bStruct.subField = struct('subSubField', {[1,2];[3,4]})
valueLeafs_b = [bStruct.subField.subSubField]; % works okay
cStruct.subField = struct('subSubField', {[1,2];[3;4]})
valueLeafs_c = [cStruct.subField.subSubField]; % error: bad arg dims
Distinct Class Structure Example
The one-line solution given previously does not work whenever the leaf node values are different class since they cannot - in general, be concatenated. However, use of arrayfun and a tricky anonymous function typically provide the required indexing technique:
dStruct.subField = struct('subSubField', {[1;2];'myString'});
valueLeafs_d = arrayfun(#(x) x.subSubField, dStruct.subField, 'UniformOutput', false)

Simultaneously assign values to multiple structure fields

I have a matlab structure that follows the following pattern:
S.field1.data1
...
.field1.dataN
...
.fieldM.data1
...
.fieldM.dataN
I would like to assign values to one data field (say, data3) from all fields simultaneously. That would be semantically similar to:
S.*.data3 = value
Where the wildcard "*" represents all fields (field1,...,fieldM) in the structure. Is this something that can be done without a loop in matlab?
Since field1 .. fieldM are structure arrays with identical fields, why not make a struct array for "field"? Then you can easily set all "data" members to a specific value using deal.
field(1).data1 = 1;
field(1).data2 = 2;
field(2).data1 = 3;
field(2).data2 = 4;
[field.data1] = deal(5);
disp([field.data1]);
A loop-based solution can be flexible and easily readable:
names = strtrim(cellstr( num2str((1:5)','field%d') )); %'# field1,field2,...
values = num2cell(1:5); %# any values you want
S = struct();
for i=1:numel(names)
S.(names{i}).data3 = values{i};
end
In simple cases, you could do that by converting your struct into a cell array using struct2cell(). As you have a nested structure, I don't think that will work here.
On the other side, is there any reason why your data is structured like this. Your description gives the impression that a simple MxN array or cell array would be more suitable.