# How can I sort a string both alphabetically and numerically?

177 views (last 30 days)
Caleb on 17 Jul 2012
Answered: Marvin Seifert on 22 Apr 2020
I'm using a list box that displays the names of the shapes I am storing in a shapefile. I'm using the sort function to list them alphabetically. This works great, but when I get to something above 9 it doesn't work quite the way I want it to. For example, my list box looks something like this:
Circle 1
Circle 10
Circle 11
Circle 12
Circle 13
Circle 2
Circle 3
Circle 4
Circle 5
Circle 6
Circle 7
Circle 8
Circle 9
Ellipse 1
Ellipse 2
Rectangle 1
.
.
.
I'd like some way to make it so that the Circles above 9 follow after the 9 instead of the 1.
##### 2 CommentsShowHide 1 older comment
Jan on 17 Jul 2012
Oleg, that's true. The leading zeros let the numerical order be the same as the alphabetical order.

Teja Muppirala on 17 Jul 2012
Very ugly, but works:
UnsortedText = {'BBB 1'; 'AAA 10'; 'AAA 9'; 'AAA 1'; 'BBB 2'; 'BBB 19'; 'BBB 9'; 'CCC 0'; 'CCC 9' ;'CCC 80'; 'CCC 7'};
R = cell2mat(regexp(UnsortedText ,'(?<Name>\D+)(?<Nums>\d+)','names'));
tmp = sortrows([{R.Name}' num2cell(cellfun(@(x)str2double(x),{R.Nums}'))]);
SortedText = strcat(tmp(:,1) ,cellfun(@(x) num2str(x), tmp(:,2),'unif',0))
There's got to be a simpler way to do this...

Ryan on 17 Jul 2012
FEX Submission "ASORT: A Pedestrian Alphanumeric String Sorter" works somewhat. I was able to sort something such as:
A = {'A 1', 'A 9', 'A 10', 'A 5'}; % In the order you asked for
But something such as:
A = {'A 1', 'B 10', 'A 4', 'B 2'};
Resulted in:
ans = A 1, B 2, A 4, B 10
There may be a better alphanumeric string sorter in the FEX that I missed in my quick search and that particular submission has some additional settings. You could sort each shape individually then concatenate back into one array if this function ends up as your best option.

Azzi Abdelmalek on 17 Jul 2012
Edited: Azzi Abdelmalek on 17 Jul 2012
list=strvcat('cir 1','cir 2','cir 10','cir 11',...
'cir 12','d 1','d 2','d 10','d 11','d 12','ee 15','dhgt 9','azs 45')
[n,m]=size(list);list1=[];list2=[];listn=[];
for k=1:n;
index = find(isstrprop(list(k,:), 'digit'), 1)
list1=strvcat(list1,list(k,1:index-1));
list2=strvcat(list2,list(k,index:end));
listn=[listn;str2num(list(k,index:end))];
end
list1c=cellstr(list1);
list2c=cellstr(list2);
listc=sortrows([list1c list2c])
listc1=listc(:,1);
list2n=str2num(char(listc(:,2)))
result1=[];k=1;result2=[];
while k<=n
ind=strmatch(listc1(k),listc1);
n1=min(ind);n2=max(ind);
result1=[result1 ;listc1(n1:n2) ]
result2=[result2; cellstr(num2str(sort(list2n(n1:n2))))]
k=k+length(ind)
end
res1=char(result1);res2=char(result2);res=[];
for k=1:n
res=strvcat(res,[strtrim(res1(k,:)) ' ' strtrim(res2(k,:))] )
end
%the result is en res variable

Marvin Seifert on 22 Apr 2020
Its an old question but still maybe I found a simpler solution:
(This works only if there is only one number in the string)
Numbers = zeros(1,length(UnsortedText));
for ii = 1:length(UnsortedText)
log = isstrprop(UnsortedText{ii},'digit')
string_name = UnsortedText{ii};
%This creates a new array only containing the numbers
numbers(ii) = string(string_name(log));
end
[~, a_order] = sort(numbers);
SortedText = UnsortedText(a_order);