3

I am running below code to sort strings and not getting the expected results.

Code:

use warnings;
use strict;

my @strArray= ("64.0.71","68.0.71","62.0.1","62.0.2","62.0.11");
my @sortedStrArray = sort { $a cmp $b } @strArray;

foreach my $element (@sortedStrArray ) {
    print "\n$element";
}

Result:

62.0.1
62.0.11   <--- these two
62.0.2    <---
64.0.71
68.0.71

Expected Result:

62.0.1
62.0.2    <---
62.0.11   <---
64.0.71
68.0.71
1

4 Answers 4

9

"1" character 0x31. "2" is character 0x32. 0x31 is less than 0x32, so "1" sorts before "2". Your expectations are incorrect.

To obtain the results you desire to obtain, you could use the following:

my @sortedStrArray =
   map substr($_, 3),
   sort
   map pack('CCCa*', split(/\./), $_),
   @strArray;

Or for a much wider range of inputs:

use Sort::Key::Natural qw( natsort );
my @sortedStrArray = natsort(@strArray);
Sign up to request clarification or add additional context in comments.

Comments

1

cmp is comparing lexicographically (like a dictionary), not numerically. This means it will go through your strings character by character until there is a mismatch. In the case of "62.0.11" vs. "62.0.2", the strings are equal up until "62.0." and then it finds a mismatch at the next character. Since 2 > 1, it sorts "62.0.2" > "62.0.11". I don't know what you are using your strings for or if you have any control over how they're formatted, but if you were to change the formatting to "62.00.02" (every segment has 2 digits) instead of "62.0.2" then they would be sorted as you expect.

Comments

0

Schwartzian_transform

This is usage of randal schwartz transofm:

First, understand, what you want:
sorting by first number, then second, then third:

let's do it with this:

use warnings;
use strict;
use Data::Dumper;
my @strArray= ("64.0.71","68.0.71","62.0.1","62.0.2","62.0.11");
my @transformedArray = map{[$_,(split(/\./,$_))]}@strArray;

=pod
  here @transformedArray have such structure: 
  $each_element_of_array: [$element_from_original_array, $firstNumber, $secondNumber, $thirdNumber];
  for example:
  $transformedArray[0] ==== ["64.0.71", 64, 0, 71];
  after that we will sort it 
  first by first number
  then: by second number
  then: by third number
=cut

my @sortedArray =  map{$_->[0]} # save only your original string.
                  sort{$a->[3]<=>$b->[3]}
                  sort{$a->[2]<=>$b->[2]}
                  sort{$a->[1]<=>$b->[1]} 
                                         @transformedArray;
print Dumper(\@sortedArray);

1 Comment

This doesn't answer the question.
0

Try the Perl module Sort::Versions, it is designed to give you what you expect.

http://metacpan.org/pod/Sort::Versions

It supports alpha-numeric version ids as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.