×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!
  • Students Click Here

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Jobs

Sort version numbers

Sort version numbers

Sort version numbers

(OP)
My company has multiple product lines and the version numbers are in different format.

For instance, one product line's version numbers may look like this: 5, 5.2, 5.11. The highest version in this example is 5.11. Therefore, we cannot simply sort them numerically.

Another product line's version numbers may look like this: 6.1.11, 6.1.22, 6.2.3, 6.2.11. This would make sorting more difficult.

And right now, the longest version number looks like this: i.j.k.l.

I want to write a piece of perl code to sort these version numbers out and it should be designed to handle future version numbers in a generic format: i.j.k. ... .m. ... .n.

I came up a solution which can handle the current situations. But it's semi-hard coded. I am hoping someone here could make it more robust.

My codes are listed below:

CODE

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $tail = 't';
my @ver = (6.1, '6.1.2', '6.1.11'); # this line is for 1st run
#@ver = (5.2, 5, 5.3, 5.12); # enable this line in 2nd run
my $info = &a2h(\@ver);
print Dumper($info);

&pickHighest($info);

# Method pickHighest() is new and is somewhat hard coded.
# 1) I am not sure if the implementation is on the right track?
# 2) If it's on the right track, how to make it more robust?

sub pickHighest {
  my $verInfo = $_[0];
  my @v1 = sort numeric (keys(%{$verInfo}));
  print "Highest Major Release: $v1[$#v1]\n";
  if(ref($verInfo->{$v1[$#v1]}) eq 'HASH') {
    my @v2 = sort numeric (keys(%{$verInfo->{$v1[$#v1]}}));
    print "Highest Sub-Major Release: $v2[$#v2]\n";
    if(ref($verInfo->{$v1[$#v1]}->{$v2[$#v2]}) eq 'HASH') {
      my @v3 = sort numeric (keys(%{$verInfo->{$v1[$#v1]}->{$v2[$#v2]}}));
      print "Highest Minor Release: $v3[$#v3]\n";
      if(ref($verInfo->{$v1[$#v1]}->{$v2[$#v2]}->{$v3[$#v3]}) eq 'HASH') {
        # To be implemented...
        # If there was a version number like this: i.j.k. ... .m.n
        # then this kind of if/else block would go ridiculously long
        # and I'd call it semi-hardcode, which I hate it.

      }
      else {
        print "This is the highest release: $v1[$#v1]\.$v2[$#v2]\.$v3[$#v3]\n";
      }
    }
    else {
      print "This is the highest release: $v1[$#v1]\.$v2[$#v2]\n";
    }
  }
  else {
    print "This is the highest release: $v1[$#v1]\n";
  }
}

exit;

# Method a2h() was discussed yesterday in this thread
# This method can handle a version number like this: i.j.k. ... .m.n

sub a2h {
  my $a = $_[0];
  my %h = ();
  foreach my $x (@{$a}) {
    my @field = split(/\./, $x);
    my $hRef = \%h;
    my $hPrev;
    my $l = scalar @field;
    for (my $i = 0; $i < $l; $i++) {
      $hPrev->{$field[$i - 1]} = $hRef = {} unless ref $hRef eq 'HASH';
      $hRef->{$field[$i]} = $i < $l - 1 ? {} : $tail unless exists $hRef->{$field[$i]};
      $hPrev = $hRef;
      $hRef = $hRef->{$field[$i]};
    }
  }
  return \%h;
}

sub numeric { $a <=> $b; }

First sample run:

CODE

% ./sortVer.pl
$VAR1 = {
          '6' => {
                   '1' => {
                            '11' => 't',
                            '2' => 't'
                          }
                 }
        };
Highest Major Release: 6
Highest Sub-Major Release: 1
Highest Minor Release: 11
This is the highest release: 6.1.11

And the 2nd sample run:

CODE

% ./sortVer.pl
$VAR1 = {
          '5' => {
                   '3' => 't',
                   '12' => 't',
                   '2' => 't'
                 }
        };
Highest Major Release: 5
Highest Sub-Major Release: 12
This is the highest release: 5.12

In summary, the results are ok. Just the implementation is not robust at all.

Thank you for your time and help.

RE: Sort version numbers

I think they way I would approach this would be to use a custom sort function.

CODE --> perl

sub soft_ver_sort {
	my @a_parts = split /\./, $a;
	my @b_parts = split /\./, $b;
	my $max_idx = ($#a_parts >= $#b_parts ? $#a_parts : $#b_parts);
	
	for (my $i = 0; $i <= $max_idx; $i++) {
		unless (defined $a_parts[$i]) { return -1;}
		unless (defined $b_parts[$i]) { return 1;}
		
		if ($a_parts[$i] < $b_parts[$i]) {
			return -1;
		} elsif ($a_parts[$i] > $b_parts[$i]) {
			return 1;
		} else {
			if ($i == $max_idx) {
				return 0;
			}
		}
	}
} 

And here's a function for the printing that you were doing, in case you needed that:

CODE --> perl

sub print_ver_info {
	my $version = shift;
	my @ver_parts = split /\./, $version;
	
	print "Highest Major Release: " . $ver_parts[0] . "\n";
	print("Highest Sub-Major Release: " . $ver_parts[1] . "\n") if $ver_parts[1];
	print("Highest Minor Release: " . $ver_parts[2] . "\n") if $ver_parts[2];
	print "This is the highest version number: " . $version . "\n";
} 

Using that custom sort function, finding the highest version becomes fairly trivial.

CODE --> perl

my @unsorted = qw/5.0.1.1 6.0.1 5.2 4.3.1.2.5 4.2.3.2.2.2.5.8.85 5.0.1 4.3.1 6.1 6.0.0.1 5  4.2.3.2.2.2.5.8.16/;
my @sorted = sort {&soft_ver_sort} @unsorted;
print "Sorting lots of versions:\n", join("\n", @sorted), "\n";
print_ver_info($sorted[-1]); 

And with your examples:

CODE --> perl

@unsorted = qw/6.1 6.1.2 6.1.11/;
print_ver_info((sort {&soft_ver_sort} @unsorted)[-1]);

print_ver_info((sort {&soft_ver_sort} qw/5.2 5 5.3 5.12/)[-1]); 

The sub used for printing would need to be modified if you ended up needing to print more of the sub versions; sorting should work regardless of how many sub version numbers are included.

RE: Sort version numbers

(OP)
Wow, it's amazing. But I have to admit that I need a bit more time to digest it.

Thank you so much, rharsh!!

p.s. Sorry for late reply. It's a long weekend in the States. Again, thank you and best regards to you.

RE: Sort version numbers

You're welcome, glad it works for you.

A few thoughts: while the custom sort is a fairly clean/simple way to approach this problem, using custom sort functions can be computationally expensive. If you're sorting huge lists of versions and performance becomes a problem, an approach similar to your original one might be the best way to go. I would probably employ recursion to 'walk through' the hash that was created with a2h() -- which would save you from having to hard code all the nested levels. But recursion is a bit more complex and possibly harder to support.

RE: Sort version numbers

A different, simpler, likely faster, approach. Of course it assumes that the highest possible version number is 99, but can be changed for 999, 9999, ...

CODE -->

my @unsorted = qw/5.0.1.1 6.0.1 5.2 4.3.1.2.5 4.2.3.2.2.2.5.8.85 5.0.1 4.3.1 6.1 6.0.0.1 5  4.2.3.2.2.2.5.8.16/;
for(@unsorted){$_=join('.',map{sprintf"%02d",$_}split(/\./,$_))}
my @sorted = sort@unsorted;
print"@sorted\n"; 

http://www.xcalcs.com : Online engineering calculations
http://www.megamag.it : Magnetic brakes for fun rides
http://www.levitans.com : Air bearing pads

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close