Reputation: 39
Perl Sort function unable to arrange array elements in my expected incremental manner
@array_sort = sort { $a <=> $b } @array
@array = ("BE_10", "BE_110", "BE_111", "BE_23", "BE_34", "BE_220", "BE_335");
@array_sort = sort { $a <=> $b } @array;
print "array_sort = @array_sort\n";
Expected result: array_sort =
BE_10 BE_23 BE_34 BE_110 BE_111 BE_220 BE_335
Actual result: array_sort =
BE_10 BE_110 BE_111 BE_23 BE_34 BE_220 BE_335
Upvotes: 0
Views: 86
Reputation: 386206
Always use use strict; use warnings;
. It would have found your problem, which is that all your strings have the numerical value of zero. Since all strings are numerically identical, the sort function you provided always returns zero. Because of this, and because Perl used a stable sort, the order of the strings remained unchanged.
You wish to perform a "natural sort", and there are modules such as Sort::Key::Natural that will do that.
use Sort::Key::Natural qw( natsort );
my @sorted = natsort @unsorted;
Upvotes: 7
Reputation: 52449
Sounds like a good case for a Schwartzian transform.
If the prefix is always going to be the same and it's just the numbers after the underscore that differ:
my @array = ("BE_10", "BE_110", "BE_111", "BE_23", "BE_34", "BE_220", "BE_335");
my @array_sort = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, (split /_/, $_)[1] ] } @array;
print "array_sort = @array_sort\n";
And if it might be different:
my @array = ("BE_10", "BE_110", "BE_111", "BE_23", "CE_34", "BE_220", "CE_335");
my @array_sort = map { $_->[0] }
sort { $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] }
map { [ $_, split(/_/, $_) ] } @array;
print "array_sort = @array_sort\n";
Basic idea is that you decompose the original array into a list of array refs holding the original element and the transformed bit(s) you want to sort on, do the sort, and then extract the original elements in the new sorted order.
Upvotes: 4