jas@ISI.EDU (Jeff Sullivan) (04/11/91)
I have an situation where I'm storing a "structure" of information
about various files in a SPLITtable string using an associative array.
For example:
$Images{"TEST.IMG"} = "120#55#4#GIF"
which might mean that the file TEST.IMG is 120x55 pixels, 4 bitplanes
deep, and is a GIF format file.
What I want to do is write a sort routine that lets me sort the
%Images elements by image length or width. Here's what I have:
sub bylen {
local ($alen, $awid, $adep, $afmt, $blen, $bwid, $bdep, $bfmt);
($alen, $awid, $adep, $afmt) = split('#', $Images{$a});
($blen, $bwid, $bdep, $bfmt) = split('#', $Images{$b});
$alen cmp $blen;
}
However, when I try to do this (on MS-PERL PL 18), I get a syntax
error at the line containing "$alen cmp $blen;"
Why?
Can't I do this? Is there a better way?
jas
--
--------------------------------------------------------------------------
Jeffrey A. Sullivan | Senior Systems Programmer
jas@venera.isi.edu | Information Sciences Institute
jas@isi.edu | University of Southern Californiatchrist@convex.COM (Tom Christiansen) (04/11/91)
From the keyboard of jas@ISI.EDU (Jeff Sullivan):
:
:I have an situation where I'm storing a "structure" of information
:about various files in a SPLITtable string using an associative array.
:For example:
:
:$Images{"TEST.IMG"} = "120#55#4#GIF"
:
:which might mean that the file TEST.IMG is 120x55 pixels, 4 bitplanes
:deep, and is a GIF format file.
:
:What I want to do is write a sort routine that lets me sort the
:%Images elements by image length or width. Here's what I have:
:
:sub bylen {
:
:local ($alen, $awid, $adep, $afmt, $blen, $bwid, $bdep, $bfmt);
:
: ($alen, $awid, $adep, $afmt) = split('#', $Images{$a});
: ($blen, $bwid, $bdep, $bfmt) = split('#', $Images{$b});
:
: $alen cmp $blen;
:
:}
:
:
:However, when I try to do this (on MS-PERL PL 18), I get a syntax
:error at the line containing "$alen cmp $blen;"
:
:Why?
Because you're running PL 18. The cmp operator wasn't in the language
then. You could use ($alen - $blen) instead of ($alen cmp $blen).
:Can't I do this? Is there a better way?
Yes: only run one split per element, instead of two per compare.
Something like this (untested):
sub sort_by_len { &sort_by_field(*Images, $[); }
sub sort_by_wid { &sort_by_field(*Images, $[+1); }
sub bynum { $a - $b; }
sub sort_by_field {
local(*table, $field) = @_;
local($_, @keys);
for (keys %table) {
push(@keys, (split(/#/, $table{$_}))[$field]);
}
sort bynum @keys;
}
@Images{&sort_by_len} is all the elements in length order;
@Images{&sort_by_wid} is all the elements in width order.
--tomchrise@hpnmdla.hp.com (Chris Eich) (04/16/91)
In comp.lang.perl, tchrist@convex.COM (Tom Christiansen) writes: sub sort_by_field { local(*table, $field) = @_; local($_, @keys); for (keys %table) { push(@keys, (split(/#/, $table{$_}))[$field]); } sort bynum @keys; } @Images{&sort_by_len} is all the elements in length order; @Images{&sort_by_wid} is all the elements in width order. This doesn't seem to work; sort_by_len returns the lengths, not the keys of the original table. You seem to want sort_by_field to return the keys of the original table, so how about this: sub sort_by_field { local(*Table, $Field) = @_; local(%Keys); foreach (keys %Table) { $Keys{(split(/:/, $Table{$_}))[$Field]} = $_; } @Table{@Keys{sort by_num keys %Keys}}; } Chris
tchrist@convex.COM (Tom Christiansen) (04/16/91)
From the keyboard of chrise@hpnmdla.hp.com (Chris Eich):
[quoting some faulty code of mine, deleted here]
:This doesn't seem to work; sort_by_len returns the lengths, not the keys
:of the original table.
:
:You seem to want sort_by_field to return the keys of the original table,
:so how about this:
:
: sub sort_by_field {
: local(*Table, $Field) = @_;
: local(%Keys);
:
: foreach (keys %Table) {
: $Keys{(split(/:/, $Table{$_}))[$Field]} = $_;
: }
: @Table{@Keys{sort by_num keys %Keys}};
: }
After staring at it until it comes into focus, yes, this is much better,
as in I think it even works, unlike my original. Mind you that I *did*
say "something like this (untested)". I consider Chris's solution here
"something like this (tested)". :-)
I know, I know: untested code never runs.
This little gem is actually a pretty nice example of several things: a
good time to use pass-by-name, inverting a table, and sorting with a
subroutine. I also like the double @{} reference here, because I think to
understand it, you really need to get your $'s and @'s and %'s down cold.
--tomchrise@hpnmdla.hp.com (Chris Eich) (04/17/91)
It's a sad day when I can't get a correction correct. :-)
I had my sort_by_field return:
@Table{@Keys{sort by_num keys %Keys}};
But it should have returned just:
@Keys{sort by_num keys %Keys};
Chris "it was Monday, OK?"