0

I was trying to think in the right way to tackle this: -I would to pass say, n elements array as argument to a subroutine. And for each element match two char types S and T and print for each element, the count of these letters. So far I did this but I am locked and found some infinite loops in my code.

use strict; use warnings;

sub main {

my @array = @_;

while (@array) {
    my $s = ($_ = tr/S//);
    my $t = ($_ = tr/T//);
    print "ST are in total $s + $t\n";
    }
}

my @bunchOfdata = ("QQQRRRRSCCTTTS", "ZZZSTTKQSST", "ZBQLDKSSSS");
main(@bunchOfdata);

I would like the output to be:

Element 1 Counts of ST = 5
Element 2 Counts of ST = 6
Element 3 Counts of ST = 4

Any clue how to solve this?

3 Answers 3

7

while (@array) will be an infinite loop since @array never gets smaller. You can't read into the default variable $_ this way. For this to work, use for (@array) which will read the array items into $_ one at a time until all have been read.

The tr transliteration operator is the right tool for your task.

The code needed to get your results could be:

#!/usr/bin/perl
use strict;
use warnings;

my @data = ("QQQRRRRSCCTTTS", "ZZZSTTKQSST", "ZBQLDKSSSS");

my $i = 1;
    
for (@data) {
    my $count = tr/ST//;
    print "Element $i Counts of ST = $count\n";
    $i++;
}   

Also, note that my $count = tr/ST//; doesn't require the binding of the transliteration operator with $_. Perl assumes this when $_ holds the value to be counted here. Your code tried my $s = ($_ = tr/S//); which will give the results but the shorter way I've shown is the preferred way.

(Just noticed you had = instead of =~ in your statement. That is an error. Has to be $s = ($_ =~ tr/S//);)

You can combine the 2 sought letters as in my code. Its not necessary to do them separately.

I got the output you want.

Element 1 Counts of ST = 5
Element 2 Counts of ST = 6
Element 3 Counts of ST = 4

Also, you can't perform math operations in a quoted string like you had.

print "ST are in total $s + $t\n";

Instead, you would need to do:

print "ST are in total ", $s + $t, "\n";

where the operation is performed outside of the string.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks @Chris. This explanation not only answers the question but also teaches me a lot of things. As a newbie to Perl, this is the best answer. Thank you.
$s = ($_ = tr/S//) actually worked as it mean $s = $_ = ($_ =~ tr/S//). That said, it needlessly clobbered the contents of @array.
@ikegami but the assignment to $_ breaks the following tr/T//, doesn't it?
Indeed, it does
0

Don't use while to traverse an array - your array gets no smaller, so the condition is always true and you get an infinite loop. You should use for (or foreach) instead.

for (@array) {
  my $s = tr/S//; # No need for =~ as tr/// works on $_ by default
  my $t = tr/T//;
  print "ST are in total $s + $t\n";
}

Comments

0

Why tr///??

sub main {
    my @array = @_;

    while (@array) {
        my $s = split(/S/, $_, -1) - 1;
        my $t = split(/T/, $_, -1) - 1;
        print "ST are in total $s + $t\n";
    }
}

3 Comments

tr/// doesn't use the regex engine, so it's a little more efficient.
@Dave Cross, Neither does split /S/ (or if it does, it's in some mode that's much faster than a normal match). Still, tr/S// should still be simpler and faster.
Split, in addition to being not as efficient, also returns one more than the number of S or Ts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.