0

I'm trying to make a little script with a nested "for" loop in perl. As I'm learning, at first I've done 3 for loops and it worked well. In order to make something more intelligent, I'd like to nested them but I don't know what is wrong.

If my input text is ABCDEFGHI I'd like to obtain

text 1 ABC DEF GHI
text 2 BCD EFG HI
text 3 CDE FGH I

But instead of it, my output is

text1 ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI
text2 BCD EFG HI BCD EFG HI BCD EFG HI
text3 CDE FGH I

Here is my script. I'm using perl 5.18.1.

use Modern::Perl '2013';

my @text1;
my @text2;
my @text3;

my $entry = shift;
my $len = length $entry;

for (my $i = 2; $i < $len; $i += 3) {
    for (my $i = 1; $i < $len; $i += 3) {
        for (my $i = 0; $i < $len; $i += 3) {
            my $text = substr($entry, $i, 3);
            push @text1, uc($text);
        }
        my $text = substr($entry, $i, 3);
        push @text2, uc($text);
    }
    my $text = substr($entry, $i, 3);
    push @text3, uc($text);
}

say "text1 @text1";
say "text2 @text2";
say "text3 @text3";

I've already taken a look around and here http://perldoc.perl.org/perlsyn.html#For-Loops

Thank you for any help

8
  • I'm assuming you're just trying to learn more? If that's the case you should know that nested for loops are something you should try to avoid if possible, they only make your programs run much slower. It's possible to do what you're trying to do with just one loop. Commented Jan 2, 2014 at 17:13
  • What makes you think that the inner loop should nor execute 27 times? Commented Jan 2, 2014 at 17:16
  • Yes. I'm trying to learn more. I thought 3 independent loops was not very intelligent. So, thank you for your advice! Commented Jan 2, 2014 at 17:16
  • @Arkadiy Everytime the more outer loop starts, the inners loops re-starts... but can't figure out what to do. Commented Jan 2, 2014 at 17:18
  • 1
    @Tetraodienne "Not very intelligent" isn't really the criterion you want to be using here; rather, "gets the job done" will serve you much better. (Nested loops are also to be avoided in general, where possible, because of their complexity cost. Consider an outer loop which runs ten times, and an inner loop which runs ten times; the process as a whole has to go through 100 iterations to complete the outer loop. Now consider an outer loop which runs ten times, and an inner loop which runs ten thousand times...) Commented Jan 2, 2014 at 17:19

2 Answers 2

1

I don't know why you'd want three nested loops (not counting substr). You only need two: One loop to determine the starting position, and one to walk through the string.

my $text = uc('ABCDEFGHI');
for my $offset (0..2) {
   my @parts;
   for (my $i=$offset; $i<length($text); $i+=3) {
      push @parts, substr($work, $i, 3);
   }

   say "@parts";
}

Or without substr. to truly demonstrate there are really only two loops:

my $text = uc('ABCDEFGHI');
my @text = split //, $text;
for my $offset (0..2) {
   my @parts;
   for my $i ($offset..$#text) {
      $parts[ ($i - $offset) / 3 ] .= $text[$i];
   }

   say "@parts";
}

Personally, I'd use

my $text = uc('ABCDEFGHI');
for (1..3) {
   my @parts = $text =~ /\G.{1,3}/sg;
   say "@parts";

   $text =~ s/^.//s;
}
Sign up to request clarification or add additional context in comments.

10 Comments

I guess it is a matter of personal preferences when using print(..)? It is very uncommon for perl.
@mpapec, As oppose to what?
print "" is more common than print("")
@mpapec, You can omit parens from sub and function calls, but it's dangerous. For example, print(($x+$y)/2) is not the same as print ($x+$y)/2.
Not when using warnings? perl -we 'print (3+3)/2'
|
0

Your three loops do not need to be nested to get your desired output:

use Modern::Perl '2013';

my @text1;
my @text2;
my @text3;

my $entry = shift;
my $len = length $entry;

for (my $i = 0; $i < $len; $i += 3) {
   my $text = substr($entry, $i, 3);
   push @text1, uc($text);
}

for (my $i = 1; $i < $len; $i += 3) {
   my $text = substr($entry, $i, 3);
   push @text2, uc($text);
}

for (my $i = 2; $i < $len; $i += 3) {        
    my $text = substr($entry, $i, 3);
    push @text3, uc($text);
}

say "text1 @text1";
say "text2 @text2";
say "text3 @text3";

You could also re-factor this a little, using two nested loops:

use Modern::Perl '2013';

my @texts = ( [], [], [] );

my $entry = shift;
my $len = length $entry;

for ( my $start = 0; $start < 3; $start++ ) {
  for ( my $i = $start; $i < $len; $i += 3 ) {
     my $text = substr($entry, $i, 3);
     push @{$texts[$start]}, uc($text);
  }
}

for ( my $start = 0; $start < 3; $start++ ) {
  say "text${start} @{$texts[$start]}";
}

As an aside: If you do nest for loops, it will be easier to read and understand your code if you use a different variable as the iterator. The three $i variables you have will work, but I had to check quite a while to make sure that wasn't your problem.

Comments

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.