Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
oh great ones,
I have an hash of array. I would like to be able to sort the hash based on the value of the array. But I cannot get to the array in the hash to be able to sort it. the example below does not work becaue I do not know how to pass the array into the sort routine.
code example :
my %colorhash = (
CCgray => ["0","0","0"],
CCwhite => ["1","0","0"],
CCgrey => ["0","2","0"],
CCBlue => ["0","0","3"],
);
foreach $colorname (keys %colorhash) {
for my $i (0.. $#{ $colorhash{$colorname} } ){
print "[$i] = $colorhash{$colorname}[$i] ";
}
print "\n";
}
my @light2dark = numsort (keys %colorhash);
sub numsort {
$colorhash{$a}[0] <=> $colorhash{$b}[0] or
$colorhash{$a}[1] <=> $colorhash{$b}[1] or
$colorhash{$a}[2] <=> $colorhash{$b}[2]
}
Re: how to sort hash of array by value
by FunkyMonk (Chancellor) on Oct 01, 2007 at 22:06 UTC
|
use Data::Dumper;
my %colorhash = ( CCgray => [ "0","0","0" ],
CCwhite => [ "1","0","0" ],
CCgrey => [ "0","2","0" ],
CCBlue => [ "0","0","3", ] );
my @light2dark = sort numsort (keys %colorhash);
print Dumper \@light2dark;
sub numsort {
$colorhash{$a}[0] <=> $colorhash{$b}[0]
or $colorhash{$a}[1] <=> $colorhash{$b}[1]
or $colorhash{$a}[2] <=> $colorhash{$b}[2];
}
Output:
$VAR1 = [
'CCgray',
'CCBlue',
'CCgrey',
'CCwhite'
];
| [reply] [d/l] [select] |
|
oops, but it still does not change the order based on the value. There is not change in the hash order.
| [reply] |
|
use Data::Dumper;
my %colorhash = ( CCgray => [ "0","0","0" ],
CCwhite => [ "1","0","0" ],
CCgrey => [ "0","2","0" ],
CCBlue => [ "0","0","3", ] );
my @light2dark = keys %colorhash;
print Dumper \@light2dark;
PS Have you enclosed your original program within <code>...</code> tags yet?
| [reply] [d/l] [select] |
Re: sort hash of array by value
by snopal (Pilgrim) on Oct 01, 2007 at 23:16 UTC
|
I'm not sure if this is homework, but you certainly won't get that code to work.
#!/usr/bin/perl
use warnings;
use strict;
my %colorhash = ( CCgray => ["0","0","0"],
CCwhite => ["1","0","0"],
CCgrey => ["0","2","0"],
CCBlue => ["0","0","3"]);
foreach my $colorname (keys %colorhash) {
for my $i (0.. $#{ $colorhash{$colorname} } ) {
print "$i = $colorhash{$colorname}[$i] ";
}
print "\n";
}
my @light2dark = sort numsort (keys %colorhash);
sub numsort {
$colorhash{$a}[0] <=> $colorhash{$b}[0]
or $colorhash{$a}[1] <=> $colorhash{$b}[1]
or $colorhash{$a}[2] <=> $colorhash{$b}[2]
}
| [reply] [d/l] |
|
Responding to my own post.
First rule:
use warnings;
use strict;
That's the annoying but seemingly impossible to avoid mantra of a good perl developer. Exclude them at your own risk, and only when you know why you are doing so. You really needed to find out where the code just would not work.
As previously remarked, your value assignment strategy does not do what you think. Since '=>' is just a sophisticated comma, your hash assignment is interpreted as:
%colorhash = (CCgray => "0",
"0" => "0",
CCwhite => "1",
"0" => "0",
etc.
I think you can see where this is going. Anonymous arrays are constructed within brackets.
As mentioned before, the quotes around clearly numeric values are unnecessary.
Next, for some reason, your example has:
$colorhash{$colorname}$i
Obviously, the array brackets are missing.
You should also research the usage of 'sort'. You defined a sort evaluation call, but didn't call sort to use it.
| [reply] [d/l] [select] |
Re: how to sort hash of array by value
by dwm042 (Priest) on Oct 02, 2007 at 14:44 UTC
|
One of the problems with providing a data set that is apparently already sorted is that it's hard to prove that the solution can indeed sort (unless you change the actual sort in use):
#!/usr/bin/perl
use warnings;
use strict;
my %colorhash = ( CCgray => ["0","0","0"],
CCwhite => ["1","0","0"],
CCgrey => ["0","2","0"],
CCBlue => ["0","0","3"], );
print "Original order of data:\n\n";
foreach my $colorname (keys %colorhash) {
printf "For key %-7s : ",$colorname;
for my $i (0.. $#{ $colorhash{$colorname} } ){
print "element[", $i,"] = $colorhash{$colorname}[$i] ";
}
print "\n";
}
print "\n\n";
my @light2dark = sort lightsort (keys %colorhash);
my @dark2light = sort darksort (keys %colorhash);
print "Order, dark is ",join(',',@dark2light), ".\n";
print "Order, light is ",join(',',@light2dark), ".\n";
sub darksort {
$colorhash{$b}[0] <=> $colorhash{$a}[0] or
$colorhash{$b}[1] <=> $colorhash{$a}[1] or
$colorhash{$b}[2] <=> $colorhash{$a}[2]
}
sub lightsort {
$colorhash{$a}[0] <=> $colorhash{$b}[0] or
$colorhash{$a}[1] <=> $colorhash{$b}[1] or
$colorhash{$a}[2] <=> $colorhash{$b}[2]
}
And the results are:
C:\Code>perl color-sort.pl
Original order of data:
For key CCBlue : element[0] = 0 element[1] = 0 element[2] = 3
For key CCgray : element[0] = 0 element[1] = 0 element[2] = 0
For key CCgrey : element[0] = 0 element[1] = 2 element[2] = 0
For key CCwhite : element[0] = 1 element[1] = 0 element[2] = 0
Order, dark is CCwhite,CCgrey,CCBlue,CCgray.
Order, light is CCgray,CCBlue,CCgrey,CCwhite.
Update: cleaner logic | [reply] [d/l] [select] |
Re: how to sort hash of array by value
by apl (Monsignor) on Oct 02, 2007 at 10:01 UTC
|
Have a subkey containing the order you wish the colors sorted in (e.g. $colorhash{CCgrey}{rank} = 2;)
Then you could later loop through colorhash testing the {rank} value. | [reply] [d/l] |
Re: sort hash of array by value
by shmem (Chancellor) on Oct 01, 2007 at 23:11 UTC
|
my %colorhash = (
CCgray => "0",
"0" => "0",
CCwhite => "1",
"0" => "0",
CCgrey => "0",
"2" => "0",
CCBlue => "0",
"0" => "3",
);
while you surely want
my %colorhash = (
CCgray => [ "0","0","0" ],
CCwhite => [ "1","0","0" ],
CCgrey => [ "0","2","0" ],
CCBlue => [ "0","0","3" ],
);
See perlref and perlreftut.
Ah, and another thing: you don't need quotes around your numbers. The above is better written as
my %colorhash = (
CCgray => [ 0, 0, 0 ],
CCwhite => [ 1, 0, 0 ],
CCgrey => [ 0, 2, 0 ],
CCBlue => [ 0, 0, 3 ],
);
--shmem
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
---------------------------- \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
| [reply] [d/l] [select] |
|
|