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

I am using 2 hoh variables in my script.refer the below example script.
my %hash1; $hash1{'1'} = 1; $hash1{'2'} = 1; $hash1{'3'} = 1; $hash1{'4'} = 1; $hash1{'5'} = 1; my %hash2; $hash2{'1'}{key} = 'a'; $hash2{'2'}{key} = 'b'; $hash2{'3'}{key} = 'a'; $hash2{'4'}{key} = 'a'; $hash2{'5'}{key} = 'b'; foreach my $key1 ( sort { $a <=> $b } keys %hash1 ) { print "key $key1 and $hash2{$key1}{key} \n"; } key 1 and a key 2 and b key 3 and a key 4 and a key 5 and b how to sort the above to get the below required output:- ------------------------------------------------------- key 1 and a key 3 and a key 4 and a key 2 and b key 5 and b
thanks

Replies are listed 'Best First'.
Re: hash sort
by choroba (Cardinal) on May 31, 2017 at 15:12 UTC
    Sort by the $hash2{$_}{key} compared by cmp, if the values are the same, use the key for the secondary sort:
    sort { $hash2{$a}{key} cmp $hash2{$b}{key} || $a <=> $b } keys %hash2

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      Thank you. It works. Anyway to sort without rewriting main loop ?
      foreach my $key1 ( sort { $a <=> $b } keys %hash1 #main loop
      Thanks
        Anyway to sort without rewriting main loop ?

        No. You must interpolate the code given to you into the loop argument:

        foreach my $key1 ( sort { $hash2{$a}{key} cmp $hash2{$b}{key} || $a <=> $b } keys %hash1 ) {

        The loop body can remain as it is, I guess.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: hash sort
by Corion (Patriarch) on May 31, 2017 at 15:21 UTC

    This is a FAQ. See perlfaq4 on "How do I sort an array by (anything)?"

Re: hash sort
by johngg (Canon) on May 31, 2017 at 17:45 UTC

    The one-to-one correspondence of the %hash1 and %hash2 keys makes me a little suspicious, where is the point of having both hashes if that's the whole of the data? I'm going to hazard a guess that %hash2 is larger than %hash1, the latter being used to select a sample from the former. I call them %data and %pick in the script below which uses rand to generate the data (and srand so that it is consistent between runs).

    use strict; use warnings; srand 12345; my %pick = map { $_ => 1 } 1 .. 5, 8, 12 .. 16, 19, 22, 25, 37 .. 41, 62, 75, 77; my @letters = ( q{a} .. q{e} ); my %data = map { $_ => { key => $letters[ rand @letters ] } } 1 .. 80; printf qq{key %2d and %s\n}, unpack q{xNXXXXXa} for sort map { pack q{aN}, $data{ $_ }->{ key }, 0 + $_ } keys %pick;

    The output.

    key 13 and a key 15 and a key 16 and a key 25 and a key 41 and a key 1 and b key 3 and b key 22 and b key 40 and b key 12 and c key 38 and c key 62 and c key 75 and c key 4 and d key 5 and d key 19 and d key 37 and d key 2 and e key 8 and e key 14 and e key 39 and e key 77 and e

    I hope this guess bears some relation to the real problems and is helpful.

    Update: A perhaps more readable alternative to the "skip one - read four - skip back five - read one" unpack template would be this:-

    printf qq{key %2d and %s\n}, reverse unpack q{aN} for sort map { pack q{aN}, $data{ $_ }->{ key }, 0 + $_ } keys %pick;

    Cheers,

    JohnGG

Re: hash sort
by thanos1983 (Parson) on May 31, 2017 at 15:34 UTC

    Hello Anonymous Monk,

    Please provide us the hashes formatted next time, it saves some time so we can answer faster.

    #!usr/bin/perl use strict; use warnings; my %hash1 = ( '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1, ); my %hash2 = ( '1' => {'key' => 'a'}, '2' => {'key' => 'b'}, '3' => {'key' => 'a'}, '4' => {'key' => 'a'}, '5' => {'key' => 'b'}, ); foreach my $key1 ( sort { $hash2{$a}{'key'} cmp $hash2{$b}{'key'} } keys %hash1) { print "key $key1 and $hash2{$key1}{key}\n"; } __END__ $ perl test.pl key 3 and a key 4 and a key 1 and a key 5 and b key 2 and b

    Something like that?

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      Ok , but its printing different 'key' everytime I run :(
      key 4 and a key 1 and a key 3 and a key 5 and b key 2 and b key 1 and a key 4 and a key 3 and a key 5 and b key 2 and b key 3 and a key 4 and a key 1 and a key 5 and b key 2 and b

        hello Anonymous Monk,

        Regarding your question:

        Ok , but its printing different 'key' everytime I run :(

        Monk choroba already provided you the answer Re: hash sort:

        #!usr/bin/perl use strict; use warnings; my %hash1 = ( '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1, ); my %hash2 = ( '1' => {'key' => 'a'}, '2' => {'key' => 'b'}, '3' => {'key' => 'a'}, '4' => {'key' => 'a'}, '5' => {'key' => 'b'}, ); foreach my $key1 ( sort { $hash2{$a}{'key'} cmp $hash2{$b}{'key'} || $a <=> $b } keys + %hash1) { print "key $key1 and $hash2{$key1}{key}\n"; } __END__ $ perl test.pl key 1 and a key 3 and a key 4 and a key 2 and b key 5 and b $ perl test.pl key 1 and a key 3 and a key 4 and a key 2 and b key 5 and b $ perl test.pl key 1 and a key 3 and a key 4 and a key 2 and b key 5 and b $ perl test.pl key 1 and a key 3 and a key 4 and a key 2 and b key 5 and b

        I read your commend under the post of monk choroba Thank you. It works. Anyway to sort without rewriting main loop ? this is why I post the reply to your question.

        Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: hash sort
by tybalt89 (Monsignor) on May 31, 2017 at 16:46 UTC
    #!/usr/bin/perl # http://perlmonks.org/?node_id=1191725 use strict; use warnings; my %hash1; $hash1{'1'} = 1; $hash1{'2'} = 1; $hash1{'3'} = 1; $hash1{'4'} = 1; $hash1{'5'} = 1; my %hash2; $hash2{'1'}{key} = 'a'; $hash2{'2'}{key} = 'b'; $hash2{'3'}{key} = 'a'; $hash2{'4'}{key} = 'a'; $hash2{'5'}{key} = 'b'; print map $_->[2], sort { $a->[1] cmp $b->[1] or $a->[0] <=> $b->[0] } map [ $_, $hash2{$_}{'key'}, "key $_ and $hash2{$_}{'key'}\n" ], keys %hash1;
      print map $_->[2], sort { $a->[1] cmp $b->[1] or $a->[0] <=> $b->[0] } map [ $_, $hash2{$_}{'key'}, "key $_ and $hash2{$_}{'key'}\n" ], keys %hash1;
      Please explain , Cant understand. This is sample code. I have many HOH in my script. Can you please assign / push $_ value in array ? I lost it because of many map functions :( :(
        Can you please assign / push $_ value in array ?

        I think tybalt89 was just trying to tie  %hash1 into a solution in line with the structures given in your OP. I, myself, don't understand the relation of the  %hash1 and  %hash2 hashes: they seem essentially identical. See johngg's post for another approach to trying to tie these two hashes together meaningfully.

        Separating out the elements a bit, see if this is clearer:

        c:\@Work\Perl\monks>perl -wMstrict -le "my %hash1 = map { $_ => 1 } 1 .. 5; ;; my %hash2; $hash2{'1'}{key} = 'a'; $hash2{'2'}{key} = 'b'; $hash2{'3'}{key} = 'a'; $hash2{'4'}{key} = 'a'; $hash2{'5'}{key} = 'b'; ;; my @sorted_top_level_hash1_keys = map $_->[0], sort { $a->[1] cmp $b->[1] or $a->[0] <=> $b->[0] } map [ $_, $hash2{$_}{'key'} ], keys %hash1 ; print qq{sorted top-level %hash1 keys: (@sorted_top_level_hash1_keys) +}; ;; for my $stlh1k (@sorted_top_level_hash1_keys) { print qq{key $stlh1k and $hash2{$stlh1k}{key}} } " sorted top-level %hash1 keys: (1 3 4 2 5) key 1 and a key 3 and a key 4 and a key 2 and b key 5 and b


        Give a man a fish:  <%-{-{-{-<

A reply falls below the community's threshold of quality. You may see it by logging in.