Search code examples
matlabsortingstructure

How to sort values of a field in a structure in 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:

enter image description here


Solution

  • 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.