Sort a structure of arrays in Matlab - matlab

I have a structure of arrays StockInfo in Matlab. The fields of the structure StockInfo are as follows:
StockInfo =
Name: {10x1 cell}
Values: [10x6 double]
Return: [10x1 double]
I need to sort StockInfo based on the field Return, so that each array in the struct is sorted accordingly. Any idea how to do it?

As I mentioned in the comment above, you question is unclear. I think you are confusing structures and structure arrays. This post might be of help.
That said, here is an example to show what I think you meant to do.
First I create a structure array with some random data:
% cell array of 10 names
names = arrayfun(#(k) randsample(['A':'Z' 'a':'z' '0':'9'],k), ...
randi([5 10],[10 1]), 'UniformOutput',false);
% 10x6 matrix of values
values = rand(10,6);
% 10x1 vector of values
returns = randn(10,1);
% 10x1 structure array
StockInfo = struct('Name',names, 'Values',num2cell(values,2), ...
'Return',num2cell(returns));
The created variable is a an array of structures:
>> StockInfo
StockInfo =
10x1 struct array with fields:
Name
Values
Return
where each element is a structure with the following fields:
>> StockInfo(1)
ans =
Name: 'Pr3N4LTEi'
Values: [0.7342 0.1806 0.7458 0.8044 0.6838 0.1069]
Return: -0.3818
Next can sort this struct array by the "return" field (each struct has a corresponding scalar value):
[~,ord] = sort([StockInfo.Return]);
StockInfo = StockInfo(ord);
The result is that the array is now sorted by the "return" values in ascending order:
>> [StockInfo.Return]
ans =
Columns 1 through 8
-0.3818 0.4289 -0.2991 -0.8999 0.6347 0.0675 -0.1871 0.2917
Columns 9 through 10
0.9877 0.3929

You can sort structure arrays based on fields with the FileExchange function nestedSortStruct (link).
B = nestedSortStruct(A, 'Return');

A solution with built-in functions only could be:
[~, ix] = sort(StockInfo.Return);
StockInfo = struct(...
'Name', {StockInfo.Name{ix}}, ...
'Values', StockInfo.Values(ix), ...
'Return', StockInfo.Return(ix));
Replace ~ with any unused identifier if your Matlab is older and does not support unused output arguments.

Related

Check if combination of field values exists in a MATLAB cell array of structs

Suppose I have a cell array containing structs, each with 3 fields.
When I encounter a new struct, I would like to check whether the values in 2 of its 3 fields match those of any struct elements in the array.
cell_array = cell(4,1)
cell_array{1}.Field1 = "ABC"
cell_array{1}.Field2 = 46
cell_array{1}.Field3 = 1648
% Would like to check if fields 1 and 2 match
% any struct in cell_array
new_struct.Field1 = "ABC"
new_struct.Field2 = 46
new_struct.field3 = 1765
Thank you.
You should use Matlab's intersect command. It finds similarities in between two lists of any sort and returns those similarities.
Should then be as simple as:
cell_array = {'ABC', '46', '1648'};
new_array = {'ABC', '46', '1765'};
[C,~,~] = intersect(cell_array,new_array)
disp(C) % C = {'ABC'} {'46'}; 2x1 cell array
% Then simply checking the length of C
if length(C) >= 2
% Perform your task
end

Extracting field from cell array of structure in matlab

I have a cell array (let's say size 10) where each cell is a structure with the same fields. Let's say they all have a field name x.
Is there a way to retreive in a vector the value of the field x for all the structure in the cell array? I would expect the function to return a vector of size 10 with in position 1, the value of the field x of the structure in cell 1 etc etc...
EDIT 1:
The structure in the cell array have 1 field which is the same for all but some others which are different.
First convert your cell array of structures, c, (with identical field names in the same order) to a structure array:
c = cell2mat(c)
Then, depending on the data types and sizes of the elements of the field, you may be able to use
[c.x]
to extract your vector of field x values in the "standard" way.
It is also possible that you can skip the conversion step and use cellfun(#(e)e.x, c) to do the extraction in one go.
The below code creates a cell array of structures, and extracts field 'x' of each structure to a vector v.
%create a cell array of structures
s1.a = 'hello';
s1.x = 1;
s2.a = 'world';
s2.x = 2;
c{1} = s1;
c{2} = s2;
v = zeros(1,2);
%extract to vector
for idx=1:size(c,2)
v(1,idx) = c{idx}.x;
end
Let's say you have
c = {s1, s2, s3, ...., sn};
where common field is 'field_1', then you have two options
Use cell2mat.
cc = cell2mat(c); % which converts your cell array of structs into an array of structs
value = [cc.field_1]; % if values are number
or
value = {cc.field_1}; % if values are characters, for example
Another option is to use cellfun.
If the field values are characters, you should set "UniformOutput" to "false"
value = cellfun(#(x) x.field_1, c, 'UniformOutput', false)
The first option is better. Also, try to avoid using cell/cellfun/arrayfun whenever you can, vectors are way faster and even a plain for loop is more effecient

operations with structure in matlab

I have a structure 1x300 called struct with 3 fields but I'm using only the third field called way. This field is, for each 300 lines, a vertor of index.
Here an exemple with 3 lines to explain my problem : I woud like to search if the last index of the first line is present in an other vector (line) of the field way.
way
[491751 491750 491749 492772 493795 494819 495843 496867]
[491753 491754 491755 491756]
[492776 493800 494823 495847 496867]
I tried with intersect function :
Inter=intersect(struct(1).way(end), struct.way);
but Matlab returns me an error :
Error using intersect (line 80)
Too many input arguments.
Error in file2 (line 9)
Inter=intersect(struct(1).way(end), struct.way);
I don't understand why I have this error. Any explanations and/or other(s) solution(s)?
Let the data be defined as
st(1).way = [491751 491750 491749 492772 493795 494819 495843 496867];
st(2).way = [491753 491754 491755 491756];
st(3).way = [492776 493800 494823 495847 496867]; % define the data
sought = st(1).way(end);
If you want to know which vectors contain the desired value: pack all vectors into a cell array and pass that to cellfun with an anonymous function as follows:
ind = cellfun(#(x) ismember(sought, x), {st.way});
This gives:
ind =
1×3 logical array
1 0 1
If you want to know for each vector the indices of the matching: modify the anonymous function to output a cell with the indices:
ind = cellfun(#(x) {find(x==sought)}, {st.way});
or equivalently
ind = cellfun(#(x) find(x==sought), {st.way}, 'UniformOutput', false);
The result is:
ind =
1×3 cell array
[8] [1×0 double] [5]
Or, to exclude the reference vector:
n = 1; % index of vector whose final element is sought
ind = cellfun(#(x) {find(x==st(n).way(end))}, {st([1:n-1 n+1:end]).way});
You propbably want to use ismember.
Consider what you are passing to the intersect/ismember functions too, struct.way isn't a valid argument, you may need to loop to iterate over each line of your struct (in this case it would be easier to have a cell array, or matrix with equal length rows).
output = zeros(300);
for ii = 1:300
for jj = 1:300
if ii ~= jj && ismember(struct(ii).way(end), struct(jj).way)
output(ii,jj) = 1;
end
end
end
Now you have a matrix output where the elements which are 1 identify a match between the last element in way in the struct row ii and the vector struct(jj).way, where ii are the matrix row numbers and jj the column numbers.

Matlab: Get Fields of Structures Inside Cells, 2D Strucutre Array

I am hoping to have a multidimensional array of structures, but I can't seem to get at the field of the contained elements. or in code:
mySample = struct('a', zeros(numA),'b', zeros(numB));
Data = cells(height,width);
disp(Data(1,1).a);
The bottom line fails with an error such as
"Improper index matrix reference."
How is a 2D array of structures done in Matlab?
There are a couple of ways to create an array of structures ("structure array" or "struct array"). Note that in a struct array, each element must have the same fields. For example, if s(1) has fields "a" and "b", then s(2)..s(n) must have fields "a" and "b".
% num rows
n = 10;
% num cols
m = 50;
% method 1, which will repeat a structure
s = struct('field1', 10, 'field2', 20);
sArray = repmat(s, n, m);
% method 2, which initializes each field to empty []
sArray(n,m) = struct('field1', [], 'field2', []);
You can expand on that to go beyond the second dimension eaisly:
sArray(n,m,p) = struct('field1', [], 'field2', []);
You could also preallocate the array and use a for-loop to set the value of each field. Additionally:
help deal
help structfun
You could also create a cell array of structures, which provides more flexibility: each structure in the cell array may have different fields.
c = cell(1,2);
c{1} = struct('a', 1, 'b', 2);
c{2} = struct('z', 0, 'q', 5);
2D array of structures can be done in 2 ways:
Cell array of structs - Heterogenic container. This means that each struct can be different.
x = {struct('a',1,'b',2), struct('c',3) ; struct() ; struct('aa',[5 6])};
disp(x{1,2});
Arrays of structs - Homegenic container. This means that all strucs must be the same - type safety.
x = struct('a',{1 2 3 ; 1 2 3},'b', {4 5 6; 7 8 9 });
disp(x(1,2));

Having trouble accessing a structure field in MATLAB

I have a structure in MATLAB. When I try to access a field, I see this displayed:
[4158x5 double]
How do I get the array itself?
My guess is that the matrix stored in your structure field is encapsulated in a cell array, so you need to use curly braces {} to index the cell contents (i.e. content indexing). Consider this example:
>> S.field1 = {1:5}; %# Create structure S with field 'field1' containing a cell
%# array which itself contains a 1-by-5 vector
>> S.field1 %# Index just the field...
ans =
[1x5 double] %# ...and you see the sort of answer you were getting
>> S.field1{1} %# Index the field and remove the contents of the cell...
ans =
1 2 3 4 5 %# ...and now you get the vector
NOTE: In newer versions of MATLAB things are displayed a bit differently, which avoids this confusion. Here's what you would see now:
>> S.field1
ans =
cell % Note now that it displays the type of data
[1×5 double]