monkfan has asked for the wisdom of the Perl Monks concerning the following question:
Most Revered Monks,
I wonder what's wrong with my code below. I can't see
anything abnormal in placing the 'print' and subroutine after
the "foreach(@test) block". But it gives a strange behaviour. It prints empty hashes after moving them. Here is the code:
Update: Subroutine included as requested. Also, before posting I have already reduced the code as simple as possible for test case. This is the simplest I can get.
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my @freq_set = (
[
'3 A B',
'2 A H',
'3 A C',
'4 A D',
'2 B C',
'2 B D',
'2 C H',
'4 C D',
'2 D H'
],
# There are some other array set
# So yes, this is meant to be an AoA
);
my $hash = {
'S1' => [ 'A', 'B', 'C','D','H','A' ],
'S2' => [ 'A', 'C', 'D','B','G','J' ],
'S3' => [ 'C', 'A', 'D','H','M','K' ],
'S4' => [ 'A', 'B', 'I','C','I','D' ]
};
# These 3 lines have strange behaviour
# If you move these three lines after foreach(@test) block
# it will print nothing, but here it prints the correct answer
my $seq = 'C D';
my %alignment = align($hash,$seq);
print Dumper \%alignment;
#-------Begin Loop---------------
my @test;
foreach my $f ( 0 .. $#freq_set )
{
foreach my $m ( 0 .. $#{$freq_set[$f]} )
{
my ($sp,$mt) = $freq_set[$f][$m] =~/(\d+)\s+(.*)/;
push @test, $mt;
}
}
my %aln;
foreach ( @test )
{
$aln{$_} = { align($hash,$_) };
}
#---------BEGIN Strange Behavior--------------
# If you move above three lines here then,
# it print *empty* hashes for both of Dumper print. Why?
print "From LOOP\n";
print Dumper $aln{'C D'};
#------------ Subroutine ---------------
sub align
{
my ($hashref,$seq) = @_;
my @in = split(/\s/,$seq);
my $test = join('(.*?)',@in);
my %hyph_padded_seq;
my %sequences;
my $reduce;
for (keys %$hashref)
{
$reduce = length(${$hashref->{$_}}[0]); last;
}
for my $key( sort {$a cmp $b} keys(%$hashref))
{
my $string = join('_',@{$hashref->{$key}});
if($string =~ $test)
{
$sequences{$key} = $hashref->{$key};
}
}
my $regex = '.*'.join('(.*)',@in).'.*';
my %in_the_running;
my $biglen = 0;
foreach my $seq (keys %sequences)
{
my @dum_in_the_running;
my @letters = @{$sequences{$seq}};
#s/.*($in[0].*$in[$#in]).*/$1/;
my ($first, $last) = (0,0);
for (@letters) { last if $_ eq $in[0]; $first++; }
for (reverse @letters) { last if $_ eq $in[$#in]; $last++; }
$last = $#letters - $last;
@letters = @letters[$first..$last];
my $asstr = join('',@letters);
if ((my @gaps) = ($asstr =~ m/$regex/o))
{
my $len = length(join('',@gaps)) / $reduce;
if ($len > $biglen)
{
unshift(@dum_in_the_running, @letters );
$in_the_running{$seq} = [@dum_in_the_running];
$biglen = length(join('',@gaps));
}
elsif ($len == $biglen)
{
unshift(@dum_in_the_running, @letters );
$in_the_running{$seq} = [@dum_in_the_running];
}
else
{
push(@dum_in_the_running, @letters );
$in_the_running{$seq} = [@dum_in_the_running];
}
}
}
#print Dumper \%in_the_running;
if ( %in_the_running )
{
my @keys_from_bigap =
( sort { @{$in_the_running{$b}} <=> @{$in_the_running{$a}}
} keys %in_the_running );
$hyph_padded_seq{$keys_from_bigap[0]} = join('',@{$in_the_running{$
+keys_from_bigap[0]}});
my @base = @{$in_the_running{$keys_from_bigap[0]}};
for my $seqno (1..$#keys_from_bigap)
{
# my @seq = split(//,$in_the_running[$seqno]);
my @seq = @{$in_the_running{$keys_from_bigap[$seqno]}};
my $count = $#base;
my @disp;
for my $q (reverse @base)
{
# Add this condition, when query is only 1
push(@seq,'-' x $reduce) if (!$seq[$#seq]);
if (($seq[$#seq] eq $q) || ($count == $#seq))
{
push(@disp, pop(@seq));
}
else
{
push(@disp, '-' x $reduce);
}
$count--;
}
$hyph_padded_seq{$keys_from_bigap[$seqno]} = join('', revers
+e(@disp));
}
}
return %hyph_padded_seq;
}
To save space, I have stored the subroutine 'align' here. Could it be a problem with the subroutine?
Re: Strange Behaviour of Two Hashes
by holli (Abbot) on May 17, 2005 at 13:59 UTC
|
Always post all *relevant* code. If the code is too long, use readmore-tags. In this case the align subroutine is the one that alters your hashes, as it seems, and thus relevant. And no. I will not follow the link to get it.
This mainly because of my laziness, but also for the sake of node completeness. What if the url is dead in some time? Nothing is as old as the url from yesterday.
| [reply] |
Re: Strange Behaviour of Two Hashes
by dragonchild (Archbishop) on May 17, 2005 at 14:00 UTC
|
To elaborate on holli's excellent comments, you need to reduce this to as simple a testcase as possible. Right now, there's too much code to work through - starting removing stuff until you remove the bug, add the thing you just removed, and that's where the bug is.
- In general, if you think something isn't in Perl, try it out, because it usually is. :-)
- "What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?"
| [reply] |
Re: Strange Behaviour of Two Hashes
by radiantmatrix (Parson) on May 17, 2005 at 14:53 UTC
|
Something is awry with your particular Perl setup, I think. I ran your code verbatim, and got the following output:
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
From LOOP
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
Is something wrong with this? For reference:
This is perl, v5.8.6 built for MSWin32-x86-multi-thread
The Eightfold Path: 'use warnings;', 'use strict;', 'use diagnostics;', perltidy, CGI or CGI::Simple, try the CPAN first, big modules and small scripts, test first.
| [reply] [d/l] [select] |
Re: Strange Behaviour of Two Hashes
by BrowserUk (Patriarch) on May 17, 2005 at 15:03 UTC
|
P:\test>457797
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
From LOOP
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
Is that what you are expecting?
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
| [reply] [d/l] |
|
Hi BrowserUk,
Thanks for answering. As I have commented inside the code.
you will see the problem, only after you move those three lines after the "foreach(@test)" block. Please try it.
It should print this:
$VAR1 = {};
From LOOP
$VAR1 = {};
| [reply] [d/l] |
|
P:\test>457797
"my" variable $seq masks earlier declaration in same scope at P:\test\
+457797.pl line 37.
"my" variable %alignment masks earlier declaration in same scope at P:
+\test\457797.pl line 38.
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
From LOOP
$VAR1 = {
'S1' => 'C-D',
'S2' => 'C-D',
'S4' => 'CID',
'S3' => 'CAD'
};
But I still don't see the problem?
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
| [reply] [d/l] |
Re: Strange Behaviour of Two Hashes
by buckaduck (Chaplain) on May 17, 2005 at 23:03 UTC
|
| [reply] [d/l] [select] |
Re: Strange Behaviour of Two Hashes
by Aragorn (Curate) on May 17, 2005 at 14:45 UTC
|
Could it be a problem with the subroutine?
That's very possible. I have no idea what it is supposed to do. It's almost 100 lines long, maybe you should try and split it up in more manageable chunks. More descriptive variable names and maybe some comments why you are doing things at key places will also help.
Arjen
| [reply] |
|
|