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

I have a code as:
#!/usr/bin/env perl use strict; use warnings; my %seen; $/=""; while (<>) { chomp; my ( $key, $value ) = split('\t', $_); my @lines = split /\n/, $key; my $key1 = $lines[1]; push( @{ $seen{$key1} }, $value ); } foreach my $key1 ( sort keys %seen ) { print join( "\t", $key, @{ $seen{$key1} } ); }
The output I am getting is not printing the $key. How can we print $key outside the while loop without foreach..Is it possible??

Replies are listed 'Best First'.
Re: preserving hash value outside the loop
by hippo (Archbishop) on May 11, 2016 at 09:48 UTC

    Yes, it is possible. Simply declare $key outside the while loop instead of inside it. See Coping with Scoping.

    Of course you'll only see the value from the last time $key is set but it's not immediately clear from your post if that's a problem for you.

      yes I declared $key outside the loop but then this is also the problem that it gives the last value set to $key. Actually I want to print each value of $key and $key1 separated by tab.

        So, why not prepend the key to the list in the first loop instead:

        #!/usr/bin/env perl use strict; use warnings; my %seen; $/ = ""; while (<>) { chomp; my ($key, $value) = split ('\t', $_); my @lines = split /\n/, $key; my $key1 = $lines[1]; $seen{$key1} //= [ $key ]; push (@{$seen{$key1}}, $value); } foreach my $key1 (sort keys %seen) { print join ("\t", @{$seen{$key1}}); }

        If this doesn't do it for you then perhaps you might state what grander problem it is that you are trying to solve and a better overall approach might be in order.

Re: preserving hash value outside the loop
by morgon (Priest) on May 11, 2016 at 09:50 UTC
    $key is from the first loop.

    In the second loop you use $key1 - you probably want to print that.

    And this is not the code you run - because of the above typo it does not compile under strict.

    It's better to post the actual code with actual test data...

      Actually I have multiple files as in the example and I want to get the output as shown in output.txt.
      1.txt @gi AGAT + AAAA 1:1.txt @gi CATT + AAAAA 3:1.txt
      2.txt @gi AGAT + AAAA 1:2.txt @gi TACA + AAAA 2:2.txt
      output.txt @gi AGAT + AAAA 2 1:1.txt 1:2.txt @gi CATT + AAAAA 3 3:1.txt @gi TACA + AAAA 2 2:2.txt
      my code is:
      #!/usr/bin/env perl use strict; use warnings; my %compare; $/=""; my $key; my $value; while (<>) { chomp; ( $key, $value ) = split('\t', $_); my @lines = split /\n/, $key; my $key1 = $lines[1]; push( @{ $compare{$key1} }, $value ); } foreach my $key1 ( sort keys %compare ) { my $tot = 0; my $file_count = @ARGV; for my $val ( @{$compare{$key1}} ) { $tot += ( split /:/, $val )[0]; } if ( @{ $compare{$key1} } >= $file_count) { print join( "\t", $key, $tot, @{ $compare{$key1} } ), "\n\n"; } }
      This gives me the count correct but $key is the last variable set. How can I print each value of $key with the total count and @{ $compare{$key1} }. I am new to perl so such a question. sorry if it sounds stupid.
        The question sound familiar to me...
        # warning windows doublequotes perl -lne "BEGIN{$/=''} @arr = split /\s+/,$_;$key=join qq(\n),@arr[0 +..3]; push @{$hash{$key}},$arr[4]; $arr[4]=~/(\d+):/? $count{$key}+= +$1:'';END{print map {qq($_ $count{$_} @{$hash{$_}} \n\n)} keys %hash + }" gen1.txt gen2.txt @gi AGAT + AAAA 2 1:1.txt 1:2.txt @gi CATT + AAAAA 3 3:1.txt @gi TACA + AAAA 2 2:2.txt perl -MO=Deparse -lne "BEGIN{$/=''} @arr = split /\s+/,$_;$key=join q +q(\n),@arr[0..3]; push @{$hash{$key}},$arr[4]; $arr[4]=~/(\d+):/? $c +ount{$key}+=$1:'';END{print map {qq($_ $count{$_} @{$hash{$_}} \n\n) +} keys %hash }" gen1.txt gen2.txt BEGIN { $/ = ""; $\ = "\n"; } LINE: while (defined($_ = <ARGV>)) { chomp $_; sub BEGIN { $/ = ''; } @arr = split(/\s+/, $_, 0); $key = join("\n", @arr[0..3]); push @{$hash{$key};}, $arr[4]; $arr[4] =~ /(\d+):/ ? $count{$key} += $1 : '???'; sub END { print map({"$_ $count{$_} @{$hash{$_};} \n\n";} keys %hash); } ; } -e syntax OK

        UPDATE still silly but no need of a separate hash to hold the count and no need of an array to accumulate the strings.

        + #fix missed { in {c} perl -lne "BEGIN{$/=''}@ar=split /\s+/,$_;$k=join qq(\n),@ar[0..3];$h +{$k}{s}.=' '. $ar[4];$h{$k}{c}+=$1 if $ar[4]=~/(\d+)/;END{print map{q +q($_ $h{$_}{c} $h{$_}{s}\n\n)} keys %h}" gen1.txt gen2.txt @gi AGAT + AAAA 2 1:1.txt 1:2.txt @gi CATT + AAAAA 3 3:1.txt @gi TACA + AAAA 2 2:2.txt # infact the dumped datastructure is easily intellegible: # in the oneliner h is for hash # s is for string # c for count (ah! never use single char variable names!) perl -MData::Dump -lne "BEGIN{$/=''}@ar=split /\s+/,$_;$k=join qq(\n), +@ar[0..3];$h{$k}{s}.=' '.$ar[4];$h{$k}{c}+=$1 if $ar[4]=~/(\d+)/;END{ +dd %h}" gen1.txt gen2.txt ( "\@gi\nAGAT\n+\nAAAA", { c => 2, s => " 1:1.txt 1:2.txt" }, "\@gi\nCATT\n+\nAAAAA", { c => 3, s => " 3:1.txt" }, "\@gi\nTACA\n+\nAAAA", { c => 2, s => " 2:2.txt" }, ) #oh well we dont need @ar at all, perl -a at the rescue: perl -lane "BEGIN{$/=''}$k=join qq(\n),@F[0..3];$h{$k}{s}.=' '.$F[4]; +$h{$k}{c}+=$1 if $F[4]=~/(\d+):/;END{print map{qq($_ $h{$_}{c} $h{$_} +{s}\n\n)} keys %h}" gen1.txt gen2.txt # ok i've nothing better to do this night.. perl -lane "BEGIN{$/=''}map{$h{$_}{s}.=' '.$F[4];$h{$_}{c}+=$1 if $F[ +4]=~/(\d+):/}join qq(\n),@F[0..3]; END{print map{qq($_ $h{$_}{c} $h{$ +_}{s}\n\n)} keys %h}" gen1.txt gen2.txt

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: preserving hash value outside the loop
by Marshall (Canon) on May 11, 2016 at 09:51 UTC
    My first suggestion would be to change $key to $key1:
    foreach my $key1 ( sort keys %seen ) { print join( "\t", $key, @{ $seen{$key1} } ); }