Article 8322 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:8322
Newsgroups: comp.lang.perl
Path: feenix.metronet.com!news.utdallas.edu!hermes.chpc.utexas.edu!cs.utexas.edu!uunet!boulder!wraeththu.cs.colorado.edu!tchrist
From: Tom Christiansen <[email protected]>
Subject: Re: OID compare
Message-ID: <[email protected]>
Originator: [email protected]
Sender: [email protected] (USENET News System)
Reply-To: [email protected] (Tom Christiansen)
Organization: University of Colorado, Boulder
References: <[email protected]> <[email protected]>
Date: Wed, 24 Nov 1993 18:20:53 GMT
Lines: 167

:-> In comp.lang.perl, [email protected] (Clark Cooper) writes:
:
:[email protected] (Craig H. Smith) writes:
:> Here is an example of sorting OIDs (this brief list of OIDs is
:> sorted).
:>
:> 1
:> 1.1
:> 1.2
:> 1.2.3
:> 2
:> 3.9.1.20.11
:> 3.10.1.1
:>
:>
:> I've written a dirty OID compare algorithm:
:> ...
:> I would like to speed it up as much as I can because my program
:> becomes slow when sorting 900+ oids.  Any hints/suggestions?
:
:Well, if the elements never exceed 255, you could convert them to
:strings with split and pack and use the regular string comparison.
:
:For instance:
:
:sub by_oid {
:    pack("C*", split('\.', $a)) cmp pack("C*", split('\.', $b));
:}
:
:@ol = ('2','1.1','3.10.1.1','1','1.2.3','3.9.1.20.11','1.2');
:
:foreach (sort by_oid @ol)
:{
:    print "$_\n";
:}
:
:If you needed to do more than one comparison or sort, it might be
:better to permanently place the related string into an associative
:array and use that for comparison.

That's still too slow.  I can make it 5x faster.


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by  on Wed Nov 24 11:18:42 MST 1993
# Contents:  mkdata sid

echo x - mkdata
sed 's/^@//' > "mkdata" <<'@//E*O*F mkdata//'
#!/usr/bin/perl

srand;

for ($n = shift || 1000; $n > 0; $n--) {
   for ($count = 1+rand(3); $count > 0; $count--) {
       print int rand 20;
       print "." if $count > 1;
   }
   print "\n";
}
@//E*O*F mkdata//
chmod u=rw,g=rw,o=r mkdata

echo x - sid
sed 's/^@//' > "sid" <<'@//E*O*F sid//'
#!/usr/bin/perl

$NTRIES = shift || 5;

while (<>) {
   push(@data, $_);
}

&bench(<<'EOF');
   print sort by_oid @data;
EOF

for (1 .. @data) {push(@idx, "1000000")}

&bench(<<'EOF');
   $mask = "%03d" x 5;
   @idx = ();
   for (@data) {
       push (@idx, sprintf($mask, split(/\./)));
   }
   for $i (sort { $idx[$a] <=> $idx[$b] } 0..$#idx ) {
       print STDOUT $data[$i];
   }
EOF

&bench(<<'EOF');
   $mask = "%03d" x 5;
   @idx = ();
   for (@data) {
       push (@idx, sprintf($mask, split(/\./)));
   }
   print STDOUT @data [ sort { $idx[$a] <=> $idx[$b] } 0..$#idx ];

EOF

&bench(<<'EOF');
   foreach (sort pby_oid @data) { print }
EOF

&bench(<<'EOF');
   @idx = ();
   for (@data) { push (@idx, pack("C*", split('\.'))) }
   print @data[sort { $idx[$a] cmp $idx[$b] } 0..$#idx];
EOF

sub pby_oid {
   pack("C*", split('\.', $a)) cmp pack("C*", split('\.', $b));
}

sub ignore {};
sub IGNORE {};

sub bench {
   local($code) = shift;
   $Method_Count++;
   local($su, $ss);

   print STDERR "method $Method_Count:\n$code\n";

   for ($try = 1; $try <= $NTRIES; $try++) {
       print STDERR "\ttry $try: ";
       ($u, $s) = times;
       eval $code;
       die "CODE ERROR: $@\n $CODE\n" if $@;
       ($nu, $ns) = times;
       printf STDERR "%8.4fu %8.4fs\n", ($nu - $u), ($ns - $s);
       $su += ($nu - $u);
       $ss += ($ns - $s);
   }
   printf STDERR "\nmethod $Method_Count, AVG: %8.4fu %8.4fs\n\n",
       $su / $NTRIES,
       $ss / $NTRIES;
}

sub by_oid {
   local($oid1, $oid2) = ($a, $b);
   local($pos, $max, @aa, @bb) = (0, 0);

   @aa = split('\.', $oid1);
   @bb = split('\.', $oid2);

   $max = ( $#aa > $#bb ? $#aa : $#bb );

   for(; $pos <= $max; $pos++) {
       (return -1) if ( !defined($aa[$pos]) );
       (return 1) if ( !defined($bb[$pos]) );
       if ( $aa[$pos] != $bb[$pos] ) {
           last;
       }
   }
   return ( $aa[$pos] - $bb[$pos] );
}
@//E*O*F sid//
chmod u=rw,g=rw,o=r sid

exit 0
--
   Tom Christiansen      [email protected]
     "Will Hack Perl for Fine Food and Fun"
       Boulder Colorado  303-444-3212