How to sort values of a field in a structure in Matlab? - matlab

In my code, I have a structure and in a field of it, I want to sort its values.
For instance, in the field of File_Neg.name there are the following values, and They should be sorted as the right values.
File_Neg.name --> Sorted File_Neg.name
'-10.000000.dcm' '-10.000000.dcm'
'-102.500000.dcm' '-12.500000.dcm'
'-100.000000.dcm' '-100.000000.dcm'
'-107.500000.dcm' '-102.500000.dcm'
'-112.500000.dcm' '-107.500000.dcm'
'-110.000000.dcm '-110.000000.dcm'
'-12.500000.dcm' '-112.500000.dcm'
There is a folder that there are some pictures with negative labels in it (above example are labels of pictures). I want to get them in the same order as present in the folder(that's mean the Sorted File_Neg.name). But when running the following code the values of Files_Neg.name load as the above example (left: File_Neg.name), while I want the right form.
I have also seen this and that but they didn't help me.
How to sort values of a field in a structure in Matlab?
Files_Neg = dir('D:\Rename-RealN');
File_Neg = dir(strcat('D:\Rename-RealN\', Files_Neg.name, '\', '*.dcm'));
% when running the code the values of Files_Neg.name load as the above example (left: File_Neg.name)
File_Neg.name:

This answer to one of the questions linked in the OP is nearly correct for the problem in the OP. There are two issues:
The first issue is that the answer assumes a scalar value is contained in the field to be sorted, whereas in the OP the values are char arrays (i.e. old-fashioned strings).
This issue can be fixed by adding 'UniformOutput',false to the arrayfun call:
File_Neg = struct('name',{'-10.000000.dcm','-102.500000.dcm','-100.000000.dcm','-107.500000.dcm','-112.500000.dcm','-110.000000.dcm','-12.500000.dcm'},...
'folder',{'a','b','c','d','e1','e2','e3'});
[~,I] = sort(arrayfun(#(x)x.name,File_Neg,'UniformOutput',false));
File_Neg = File_Neg(I);
File_Neg is now sorted according to dictionary sort (using ASCII letter ordering, meaning that uppercase letters come first, and 110 still comes before 12).
The second issue is that OP wants to sort according to the magnitude of the number in the file name, not using dictionary sort. This can be fixed by extracting the value in the anonymous function applied using arrayfun. We use str2double on the file name, minus the last 4 characters '.dcm':
[~,I] = sort(arrayfun(#(x)abs(str2double(x.name(1:end-4))),File_Neg));
File_Neg = File_Neg(I);
Funnily enough, we don't want to use 'UniformOutput',false any more, since the anonymous function now returns a scalar value.

Related

Modifying output names using for in Matlab

I'm trying to change output names using for in Matlab. I'm reading daily files, so I'd like the outputs to also have the day printed on their name. This is a simplification of what I've got so far:
day=['1','2','3','4','5'];
for i=1:length(day)
namefile=['datafromday',num2str(day(i)),'.nc'];
[var1,var2,var3]=read(namefile);
var1_*=var1;
var2_*=var2;
var3_*=var3;
end
The * marks where I want to have the day number on. I've tried the same combination as in namefile but was unsuccessful.
Any ideas? Thank you!
I suggest you use a 2D cell array instead of separate variables. First index of the cell array will correspond to day, second will correspond to namefile. (Also, don't use var as a variable name, as there is a function with that name).
day = ['1','2','3','4','5'];
vars = cell(numel(day),3); %// change "3" as needed
for i = 1:length(day)
namefile = ['datafromday',num2str(day(i)),'.nc'];
[vars{i,:}] = read(namefile);
%// Now the file names are in vars{i,1}, vars{i,2} etc
end

Matlab bad cell reference operation when if statement

I have a <850x1> cell called x. Each of the individual structures has a 'Tag' name and 'Data' cell with <7168x1 double> data values.
(i.e.
x{1,1}.Tag = 'Channel1', x{1,1}.Data= <7168x1 double>)
So, I want to go through the x cell, identify the structures with 'Channel1' Tag names and pull out that structure's data. Then, combine the data into a cell called Ch1. Here is my approach so far:
n=1:850
if x{n,1}.Tag == 'Channel1'
Ch1{:,n} = x{n,1}.Data;
end
However, this gives an error: Bad cell reference operation.
Any ideas what may be going wrong?
There are 2 issues here. First, your if statement will compare each entry in the string x{n,1}.Tag to each entry in the string 'Channel1'. If the dimensions are not the same, you will get an error. To fix this, you could use the string compare function, strcmp. The other issue is that you are assigning n to all values between 1 and 850 at once. This is the issue that is producing the actual error you are seeing. Instead, you want to step through each of these values one at a time with a for loop. I would suggest trying the following code:
for n=1:850
if strcmp(x{n,1}.Tag, 'Channel1')
Ch1{:,n} = x{n,1}.Data;
end
end

Matlab: Understanding a piece of code

I have a matlab code which is for printing a cell array to excel. The size of matrix is 50x13.
The row 1 is the column names.
Column 1 is dates and rest columns are numbers.
The dateformat being defined in the code is:
dFormat = struct;
dFormat.Style = struct( 'NumberFormat', '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(#_)' );
dFormat.Font = struct( 'Size', 8 );
Can someone please explain me what the dFormat.Style code means ?
Thanks
The first line creates an empty struct (struct with no fields) called dFormat. A structure can contain pretty much anything in one of its fields, including another structure. The second line adds a field called 'Style' to the dFormat struct and sets it equal to another struct with a field called 'NumberFormat'. The 'NumberFormat' field is set equal to that long string of characters. You now have a structure of structures. The third line is similar to the second.
Note that the first line isn't really necessary unless dFormat already exists and it needs to be "zeroed out" as dFormat.Style with create it implicitly. However, using the struct function can make code more readable in some cases as objects use a similar notation for access methods and properties. In other words, all of your code could be replaced with:
dFormat.Style.NumberFormat = '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(#_)';
dFormat.Font.Size = 8;
See this video from the MathWorks for more details and this list of helpful structure functions and examples.
#horchler already elaborated on structs, but I imagine you may actually be more interested in the content of this structs Style field.
In case you are solely interested in _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(#_), that does not really look like something MATLAB related to me.
My best guess is that this code is used to later feed some other program, for examle to build an excel file.

PostgreSQL CASE: position within text array

I am currently successfully using a CASE expression to update an empty column based on attributes from other columns. For example
UPDATE table SET cat = CASE
WHEN term = '{"Boulder"}' then 'Boulder'
However, I need to do the same but on an text array and particularly when an element is in a specific position within that array.
For example if the data looks like
{"Boulder, Tree, Bush"}
WHEN position('Tree' in term) > 0 then 'Boulder'
But I receive an error message
function pg_catalog.position(character varying[], unknown) does not exist
I have used position in a function before so I am not sure why PostgreSQL does not like it in this situation.
Is there a way to using a CASE expression whilst determining the position of a text element within an array.
Apparently your term column is defined as an array, e.g. varchar[]. The position function only works with scalar values, not with arrays.
If you want to test if an element is contained in an array you need to use a different operator: #>
update foobar
set cat = 'Boulder'
where term #> '{"Boulder"}'
The expression '{"Boulder"}' creates an array with a single element. It's equivalent to array['Boulder'] (which I find more readable). So the above where condition updates all rows where the array term contains all elements of the array on the right hand side of the operator. In this case it's only a single element you are testing for.
More details about the array functions and operators can be found in the manual: http://www.postgresql.org/docs/current/static/functions-array.html
Edit after the requirements have changed
To find and update only those where boulder is in the first, second or third place, you can use this:
update foobar
set cat = 'Boulder'
where 'Boulder' in (term[1], term[2], term[3]);

How do I sort a structure array based on one field in MATLAB?

I previously posted on how to display and access structure array content. The file consisted of states, capitals, and populations. Now I'm having trouble in created a new structure by organizing these states in alphabetical order. I did this by the sortrows function, and I tried pairing up the values of population and the capitals with the alphabetical states, but I can't seem to get it to be an array. I want it to be an array so I can write it to a file. This is what I have so far:
fid=fopen('Regions_list.txt')
file=textscan(fid,'%s %s %f','delimiter',',')
State=file{1}
Capital=file{2}
Population=num2cell(file{3})
sortedStates=sortrows(State)
n=length(State)
regions=struct('State',State,...
'Capital',Capital,...
'Population',Population)
for k=1:n;
region=sortedStates(k);
state_name={regions.State};
state_reference=strcmpi(state_name,region);
state_info=regions(state_reference)
end
I hope I'm making myself clear.
Use this to sort the cell array read in (no conversion needed), then write to file with this.
With respect to your sorting issue, The function SORT will return as its second output a sort index which can be used to apply the same sort order to other arrays. For example, you could sort your arrays before you create your structure array:
[sortedStates,sortIndex] = sort(State);
regions = struct('State',sortedStates,...
'Capital',Capital(sortIndex),...
'Population',Population(sortIndex));
Or you could apply your sorting after you create your structure array:
regions = struct('State',State,...
'Capital',Capital,...
'Population',Population);
[~,sortIndex] = sort({regions.State});
regions = regions(sortIndex);
However, I'm not sure what you mean when you say "I want it to be an array so I can write to a file."