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 California
tchrist@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. --tom
chrise@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. --tom
chrise@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?"