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

Hello Monks, Im trying to convert a sequence of 1's and 0's into s new sequence which is the length of 1's, so;

@a = (0,0,1,1,1,0)

needs to be

@b = (0,0,3,0)

I then need to go one step further, changing the new sequence into letters, where each letter corresponds to a different number (assuming my maximum number of 1's in a row is 15) My input is a file of 1's and 0's. Ive tried this code, but it wont work!

my @result = split '', 'abcdefghijklmno'; my @arg1 = (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); my %rules; # Build the rules hash $rules{$arg1[$_]} = $result[$_] for 0 .. $#result; my @newseq = (); my $run = 0; my @bin = (); while ( <INFILE> ) { @bin= split(/ /, $_); for (my $i=0;$i<$#bin;$i++) { if ($bin[$i]==0){ $run=0; push @newseq,$run; } if ($bin[$i]==1 && $bin[$i+1]==0){ $run++; push @newseq, $run; } else { $run++; } } } for (1 .. $#newseq) { if ( $_ % 80 != 0){ print "$rules{$newseq[$_-1]}"} else{ print "$rules{$newseq[$_-1]}\n"; } }
The @newseq array is always empty, I must be doing something wrong and initializing in the wrong place, but I cant see where. Any ideas on a better way to do this would also be appreciated. Thanks.

Replies are listed 'Best First'.
Re: length of 1's
by ikegami (Patriarch) on Apr 27, 2009 at 03:57 UTC

    Is that your real program? You never open INFILE, so you never read anything from it, so you never add anything to @newseq. Use use strict; and use warnings;. You would have gotten

    Name "main::INFILE" used only once: possible typo at a.pl line 18. readline() on unopened filehandle INFILE at a.pl line 18.

    instead of having to waste your time waiting for a reply here.

    Other problems:

    • for (my $i=0;$i<$#bin;$i++)
      ends too soon. You want
      for (my $i=0;$i<@bin;$i++)
      or
      for (my $i=0;$i<=$#bin;$i++)
      Or even better,
      for my $i (0..$#bin)

    • $run++ is executed too often. Change
      if ($bin[$i]==1 && $bin[$i+1]==0)
      to
      elsif ($bin[$i]==1 && $bin[$i+1]==0)

    • What if the last one isn't followed by a zero?
      elsif ($bin[$i]==1 && $bin[$i+1]==0)
      should be
      elsif ( $bin[$i]==1 && ($i==$#bin || $bin[$i+1]==0) )

    • What if you get a sequence of 16 ones?

    • You don't need %rules or @arg1.
      $rules{$newseq[$_-1]}
      is a weird way of saying
      $results[$newseq[$_-1]]

    • The "1 .." (instead of "0 ..") and the "- 1" look very suspicious in the last loop. Can't say for sure without knowing what you want.

      use warnings results in this warning;

      Use of uninitialized value in numeric eq (==) at bin2runs.pl line 32

      Without any better ideas, I tried changing the ==0 to ==$zero, and initializing $zero earlier (my $zero =0), to no success. Other than the warnings the script works.

        Not for the code you gave. Line 32 is a blank line. I can't speculate about code I know nothing about.
Re: length of 1's
by vinoth.ree (Monsignor) on Apr 27, 2009 at 04:04 UTC

    You need to use chomp after you get each line from the file to remove the newline character

    chomp;
    Vinoth,G
Re: length of 1's
by roubi (Hermit) on Apr 27, 2009 at 03:38 UTC
    Your code expects your 0s and 1s to be space separated but you do not mention that fact in your post. Is it? If not @bin may be empty as well.
Re: length of 1's
by jwkrahn (Abbot) on Apr 27, 2009 at 10:42 UTC

    From your description, this should be close to what you want:

    my $newseq = do { local $/; <INFILE> }; $newseq =~ tr/01//cd; $newseq =~ tr/0/a/; $newseq =~ s/(1+)/ chr length( $1 ) + ord 'a' /eg; print "$_\n" for $newseq =~ /.{0,80}/g