I would like to sort elements in a comma-separated list. The elements in the list are structs and I would like the list to be sorted according to one of the fields in the struct.
For example, given the following code:
L = {struct('obs', [1 2 3 4], 'n', 4), struct('obs', [6 7 5 3], 'n', 2)};
I would want to have a way to sort L by the field 'n'. Matlab's sort function only works on matrices or arrays and on lists of strings (not even lists of numbers).
Any ideas on how that may be achieved?
Thanks,
Micha
I suggest you do this in three steps: Extract 'n' into an array, sort the array and consequently reorder the elements of the cell array.
%# get the n's
nList = cellfun(#(x)x.n,L);
%# sort the n's and capture the reordering in sortIdx
[sortedN,sortIdx] = sort(nList);
%# use the sortIdx to sort L
sortedL = L(sortIdx)
This is a bit of an aside, but if all of the structures in your cell array L have the same fields (obs and n in this case), then it would make more sense to store L as a 1-by-N structure array instead of a 1-by-N cell array of 1-by-1 structures.
To convert the 1-by-N cell array of structures to a 1-by-N structure array, you can do the following:
L = [L{:}];
Or, you can create the structure array directly using one call to STRUCT instead of creating the cell array of structures as you did in your example:
L = struct('obs',{[1 2 3 4],[6 7 5 3]},'n',{4,2});
Now the solution from Jonas becomes even simpler:
[junk,sortIndex] = sort([L.n]); %# Collect field n into an array and sort it
sortedL = L(sortIndex); %# Apply the sort to L
For what it's worth, here is the solution in Python:
L = [{'n': 4, 'obs': [1, 2, 3, 4]}, {'n': 2, 'obs': [6, 7, 5, 3]}]
L.sort(lambda a,b: a['n'].__cmp__(b['n']))
# L is now sorted as you wanted
Related
In MATLAB, I want to retrieve the value of a particular position in a matrix through a vector
v = [1, 2, 3, 4];
A(v)
A(v(:))
how can I do that?
The length of the vector is not fixed so I cannot hardcode A(v(1), v(2), v(3), v(4)).
Convert v to a cell-array (say cellv) using num2cell and then extract elements of cellv as comma separated values to index A and implement A(v(1), v(2), v(3), v(4), ... v(n)) in a generalised manner.
cellv = num2cell(v);
A(v{:})
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
Think I have an array like
A = { 1,2,3,4,5,6}
I need to get the position of 4 in this array.
I tried,
p = find(A==4)
Please help.
If you really need a cell array (for example because the cells can contain vectors of different sizes):
A = {1, [1 2 3], 4, [1 2], [3 4]}; %// example cell array
sought = [1 2]; %// sought contents
index = find(cellfun(#(x) isequal(x, sought), A));
you created a cell-array instead of a normal vector.
Try:
A = [1,2,3,4,5,6]
find(A==4)
Cell arrays are great to store variables with different types.You could, for example, create a cell array that contains strings as well as digits.
If you have only digits in your array you should defintely use normal arrays.
These are defined by [ ] instead of { }
As you have defined a cell array you need to convert it to a numeric array for find to work, fortunately this is simple to achieve with a couple of well placed brackets.
A = { 1,2,4,3,5,6};
find([A{:}]==4)
ans =
3
So A{:} writes out the numeric values from your array and the [] contains the output for find to work.
p.s. I re-arranged the numbers in A to show that it was working as '4' is now in position 3 to provide a better test.
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));
My problem is in how to sort an array of cells considering only the first element of each cell in that vector:
array_A={[3 1 5] [1 6 2] [2 4 1]}
I want to sort array_A, by the first element of each cell like this:
array_A={[*1* 6 2] [*2* 4 1] [*3* 1 5]}
Do you have any idea on how can I solve this, in a way that it can be done recursively for thousands of cells?
The easiest might just be to catenate array_A to create a numeric array and sort based on that. If the vectors are long, or of different lengths, you may want to extract the first element of each element of the cell array first and sort that.
In other words:
%# extract the first number from each element of array_A
firstElement = cellfun(#(x)x(1),array_A);
%# sort (the ~ discards the first output argument of sort)
[~,sortIdx] = sort(firstElement);
%# sort array_A using the proper sort order
array_A_sorted = array_A(sortIdx);