monkfan has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,
I have this HoA reference.
my $HoA_ref = {'GAT' => [2, ['ttt',-3,1],['ttc',-3,3],['ccc',-1,2]], 'AAA' => [13,['aaa',-1,2],['atg',-2,2]], 'TTT' => [11,['tta',-2,1],['atc',-3,3]] }; # Need to print 'AAA' slice only coz have'13' as highest value
Would like to print *only* the top sorted Hash based on the zeroeth element of the value.
Sucht that it gives *only*
AAA 13: aaa,-1,2 atg,-2,2
I tried this function but of no avail:
#namely how can I pick only the topmost with this subroutine #besides some reference error that I encounter. sub print_zHoA { my ($HoA) = @_; foreach my $mc (sort {$HoA{$a}[0] <=> $HoA{$b}[0]} keys %$HoA){ print "$mc $HoA{$mc}[0]:\n"; foreach my $i (0.. $#{$$HoA{$mc}}) { print "$$HoA{$mc}[$i]->[0],$$HoA{$mc}[$i]->[1],$$HoA{$mc}[$i]- +>[2]"; } print "\n"; } }
How can I go about it?
Thanks so much beforehand.
Regards,
Edward

Replies are listed 'Best First'.
Re: Printing a Hash Slices problem
by friedo (Prior) on Feb 28, 2005 at 16:57 UTC
    If I understand your requirements correctly, something like the following should work:

    my $HoA_ref = {'GAT' => [2, ['ttt',-3,1],['ttc',-3,3],['ccc',-1,2]], 'AAA' => [13,['aaa',-1,2],['atg',-2,2]], 'TTT' => [11,['tta',-2,1],['atc',-3,3]] }; # Find key associated with highest value my ($key, $max); for(keys(%{$HoA_ref})) { if( $HoA_ref->{$_}[0] > $max ) { $key = $_; $max = $HoA_ref->{$_}[0]; } } # output the item with the max value print "$key $max:\n"; my @out = @{ $HoA_ref->{$key} }; # skip zeroth element for(1..$#out) { print join ',', @{ $out[$_] }, "\n"; }
      Or (because I like slices)
      # skip zeroth element for(@out[1..$#out]) { print join ',', @$_, "\n"; }
      or even
      # skip zeroth element print "$_\n" for map { join ',', @$_ } @out[1..$#out];

      Caution: Contents may have been coded under pressure.
Re: Printing a Hash Slice problem
by dorward (Curate) on Feb 28, 2005 at 17:21 UTC

    If you don't need to keep the key around, you can do this:

    sub print_zHoA { my $HoA = shift; my @values = sort { $b->[0] <=> $a->[0] } values %{$HoA}; return $values[0]; }

    Note, however, that while the code is short, it isn't as efficient as it could be since it puts all the hash slices in order rather then just finding the highest.

      ... and then the "Duh" moment strikes and I see how to preserve the key.

      sub print_zHoA { my $ref = shift; my %HoA = %{$ref}; my @values = sort { $HoA{$b}->[0] <=> $HoA{$a}->[0] } keys %HoA; return { $values[0] => $HoA{$values[0]} }; }
Re: Printing a Hash Slice problem
by deibyz (Hermit) on Feb 28, 2005 at 17:32 UTC
    I think your sort routine is missing the "->" to dereference the hash, if you're using a hashref.

    If you want to use the sort approach (less efficient, as [id://dorward] noted), you can do something like that:

    #!/usr/local/bin/perl use strict; use warnings; my $HoA = {'GAT' => [2, ['ttt',-3,1],['ttc',-3,3],['ccc',-1,2]], 'AAA' => [13,['aaa',-1,2],['atg',-2,2]], 'TTT' => [11,['tta',-2,1],['atc',-3,3]] }; my $key = (sort {$HoA->{$a}[0] <=> $HoA->{$b}[0]} keys %$HoA)[-1]; my $value = shift @{$HoA->{$key}}; # get the first element print "$key $value:\n"; # Print it for (@{$HoA->{$key}}){ # And loop through the rest local $,=","; local $\="\n"; print @$_; } __END__ __OUTPUT__ AAA 13: aaa,-1,2 atg,-2,2
Re: Printing a Hash Slice problem
by Taulmarill (Deacon) on Feb 28, 2005 at 18:09 UTC
    this should do the trick:
    use strict; use warnings; my $HoA_ref = {'GAT' => [2, ['ttt',-3,1],['ttc',-3,3],['ccc',-1,2]], 'AAA' => [13,['aaa',-1,2],['atg',-2,2]], 'TTT' => [11,['tta',-2,1],['atc',-3,3]] }; sub print_zHoA { my ($HoA) = shift; my $mc = (sort {$$HoA{$a}[0] <=> $$HoA{$b}[0]} keys %$HoA)[-1]; print "$mc $$HoA{$mc}[0]:\n"; for my $i ( 1 .. $#{$$HoA{$mc}} ) { print join( ',', @{$$HoA{$mc}[$i]} ), "\n"; } } print_zHoA($HoA_ref);
      Dear Taumarill,

      Thanks for answering. Just a question regarding your code above:
      my $mc = (sort {$$HoA{$a}[0] <=> $$HoA{$b}[0]} keys %$HoA)[-1];
      1. What does '-1' means here?
      2. Why '=' sign? Basically what does the statement above means?
      How does it work?

      Regards,
      Edward

        [-1] is a negative array index, which lets you count from the other end of an array. $array[-1] is the same as [reverse @array]->[0] or $array[$#array]

        <=> is a comparison operator for numbers, similar to cmp for strings. (see perlop or the sort documentation)

Re: Printing a Hash Slice problem
by osunderdog (Deacon) on Feb 28, 2005 at 17:34 UTC

    Best I could do. But it's destructive to the hash.

    use strict; my $HoA_ref = {'GAT' => [2, ['ttt',-3,1],['ttc',-3,3],['ccc',-1,2]], 'AAA' => [13,['aaa',-1,2],['atg',-2,2]], 'TTT' => [11,['tta',-2,1],['atc',-3,3]] }; sub print_zHoA { my ($HoA) = shift; foreach my $mc (sort {$HoA->{$a}->[0] <=> $HoA->{$b}->[0]} keys %$ +HoA){ print "$mc $HoA->{$mc}->[0]:\n"; print join(',', map {$_->[0]} splice( @{$HoA->{$mc}}, 1)) . "\n" +; } } print_zHoA($HoA_ref);

    I think the thing that was throwing you is that $x->[][] is syntactic sugar for $x->[]->[]. Another possible confusing point is that in your function, you are receiving a reference to a HoA rather than a HoA. So anywhere you use $HoA{$x} it should be $HoA->{$x}.


    "Look, Shiny Things!" is not a better business strategy than compatibility and reuse.