k> I want to sort an array of records. The records are strings
k> consisting of tab-delimited fields. The field I want to sort by
k> represents a float (in ASCII). Furthermore, the first field
k> represents the record's (1-based) position in the array. Therefore,
k> after sorting the array, I must update the value of the first field
k> in each record.
k> Currently, I do something like:
k> my $i = 1;
k> sort { $b->[5] <=> $a->[5] }
k> but I would like to use the Guttman-Rosler Transform (packed-default
k> sort) instead.
k> It seems to me that the best way to extract the sort field, and to
k> update the position field afterwards, is to first transform the
k> record into an anonymous array (as I do above). The problem is
k> that I don't know how to turn this anonymous array into a payload
k> suitable for the packed-default sort, and how to append it to the
k> packed key. Any help would be much appreciated.
since you need to change a field later, why not keep the split records
around and just sort on their floats with their index numbers as the
payload.
the paper at http://www.*-*-*.com/
packed sort (either endian) for a float. just append the index number
and that will be used to reorder the input records to output
records. and you can then add the updated index number (similar to what
you do above.
this is rough (untested) code for how i would do it. it could be
converted to the tighter map/sort/map if desired but it is fairly
complex so i would keep it this way.
# this was copied from the sort paper. it could be improved to assign
# into the symbol table one of two different subs. it would make the
# endian test be purely compile time.
BEGIN {
my $big_endian =
pack('N', 1) eq
pack('L', 1);
sub double_sort ($) {
($big_endian ?
pack 'd', $_[0] :
reverse pack 'd', $_[0]) ^
($_[0] < 0 ? "\xFF" x 8 :
"\x80" . "\x00" x 7)
}
Quote:
}
# untested but should work and be faster than the above:
BEGIN {
no strict 'refs' ;
*{'double_sort'} = pack('N', 1) eq pack('L', 1) ?
sub ($) { pack 'd', $_[0] ^
($_[0] < 0 ?
"\xFF" x 8 : "\x80" . "\x00" x 7)
} :
sub ($) {
reverse pack 'd', $_[0] ^
($_[0] < 0 ?
"\xFF" x 8 : "\x80" . "\x00" x 7)
} ;
}
# this just splits the records into a LoL
# this creates a packed sort key based on the float with the index for payload
# this gets the sorted indices and uses them to to index into the
# pre-sorted records. it then assigns the new index number and makes a
# tabbed record out of it.
my $i ;
my $row = $pre_sort_records[ $_ ] ;
$row->[0] = ++$i ;
--
----- Stem and Perl Development, Systems Architecture, Design and Coding ----
Search or Offer Perl Jobs ---------------------------- http://www.*-*-*.com/
Damian Conway Perl Classes - January 2003 -- http://www.*-*-*.com/