Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Huge simple problem

by Anonymous Monk
on Aug 05, 2009 at 22:14 UTC ( #786243=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

When I run the following,
$query = "bush and clinton and bush and obama and huckabee"; @searchTexts = split (/and|or/i,$query); for ($i = 0; $i <= @searchTexts +1 -1; $i++) { @searchTexts[$i] =~ s/^\s+//; @searchTexts[$i] =~ s/\s+$//; print @searchTexts[$i]."\n"; }
the program loops endlessly. What am I doing wrong? Thanks in advance

Comment on Huge simple problem
Download Code
Re: Huge simple problem
by Anonymous Monk on Aug 05, 2009 at 22:23 UTC
    Never mind. I see my problem now. Duh! The <= should be <. And to think that I spent over an hour on that.
      Perhaps the Basic debugging checklist would help shorten the debug cycle in the future, particularly tips #1 and #2:

      #1 use warnings; would have spewed many warnings which may have lead you to your problem.

      #2 print "i = $i\n"; inside your for loop

      I see my problem now...

      Bonus points if you actually explain why using '<=' makes the loop run "endlessly" (until available memory is exhausted, that is)   :)

      (Probably obvious to most monks, but maybe not to everyone...)

        Bonus points if you actually explain why
        Since the OP has not chimed in, I will make an attempt at an explanation.
        Probably obvious to most monks
        I freely admit that it was not obvious to me. I'm glad you prompted me to think about it further.

        Here goes. It is a case of modifying an array in a for loop. Before the for loop, the @searchTexts array contains 5 elements (indices: 0-4). The 1st 5 times though the loop, the array size remains constant at 5. Now, let's look at the end condition of the loop:

        $i <= @searchTexts +1 -1;

        which is just a slightly obfuscated form of:

        $i <= @searchTexts;

        Since the array is evaluated in scalar context, @searchTexts is the same as scalar @searchTexts, which returns the current size of the array. The 1st 5 times through the loop, the size is 5, and therefore the end condition is satisfied (the 5th time , $i is 4, which is less than or equal to 5). At the end of the 5th time through the loop, $i increments to 5, which is still less than or equal to 5. This causes the loop to be executed a 5th 6th time, which in turn causes the array to grow by 1 because of this line:

        @searchTexts[$i] =~ s/^\s+//;

        which resolves to this:

        @searchTexts[5] =~ s/^\s+//;

        From there on, the array continues to grow by one each time through the loop because the end condition is dependent on the array size.

Re: Huge simple problem
by dreadpiratepeter (Priest) on Aug 05, 2009 at 22:43 UTC
    May I suggest that you learn to use the foreach loop in Perl, rather than the c-style for loop.
    my @searchTexts = split (/and|or/i,$query); foreach my $text (@searchtexts) { $text =~ s/^\s+//; $text =~ s/\s+$//; print "$text\n"; }
    and in a loop this simple I would just use $_
    foreach (split /and|or/i,$query) { s/^\s*(.*?)\s*$/$1/; print "$_\n"; }
    or reduce it even further with a map and a join (depends on circumstance, if I'm the not only maintainer I'd probably use the above version)
    print join("\n",map {/^\s*(.*?)\s*$/;$1} split(/and|or/i,$query)) . "\ +n";
    all the above code is untested.

    update: also you could first clean the ends of $query (with s/^\s*(.*?)\s*$/). Then if you change the slip condition to /\s*(?:and|or)\s*/ you can skip the map:
    print join("n\",split(/\s*(?:and|or)\s*/,$query)) . "\n";
    of course at this point you can skip the whole split and use:
    $query =~ s/\s*(?:and|or)\s*/\n/g; print "$query\n";
    A final note, all these will fail horribly if your data has and/or imbedded in words. ie world. You probably want to split on /\s+(?:and|or)\s+/ or /\s*\b(?:and|or)\b\s*/

    Phew, now I need a nap


    -pete
    "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."
      Thanks for the help!
      May I suggest that you learn to use the foreach loop in Perl, rather than the c-style for loop.

      Do note that foreach is just an alternate spelling of for. for my $text (@searchtexts) { ... } is exactly equivalent to foreach my $text (@searchtexts) { ... }.

      Either way, though, I can't remember the last time I used a C-style for loop in Perl. for ( [list] ) is so much nicer and avoids all those nasty off-by-one errors.

        I second this advice, and (missingthepoint posting anonymously), ++ to you both for helpful replies (when I remember what I changed my password to).

        Also, may I suggest you use strict and use warnings? (put those two lines at the top of your code). It will save you a lot of time - I speak from painful experience :|

        One final word: it appears as though you're trying to get the number of elements in @a by writing @a +1 -1. That's contorted - you can just say $i <= @a, since <= puts its operands (that is, $i and @a) in scalar context, and for the array, produces the number of elements it contains.

        You can improve that even further, too. As it stands you have an off-by-one error - looping from $i = 0 to $i = @array<c> will put you one element beyond the end. If you need a C-style for loop, you can write: <c>for ($i = 0; $i < @a; $i++) { ... and be done with it. :)

        But in your situation, you would be better served just doing what dsheroh++ said and using a plain for: for my $element (@a) { <do something with element> ...

        Don't hesitate to let me know if that was unclear. :)

        I always say foreach when doing (@a) type loops and for when doing c-style loops. helps make the code a little more self-documenting


        -pete
        "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."
Re: Huge simple problem
by leighsharpe (Monk) on Aug 06, 2009 at 03:37 UTC
    Shouldn't that be:
    $searchTexts[$i] =~ s/^\s+//; $searchTexts[$i] =~ s/\s+$//; print $searchTexts[$i]."\n";
    Instead of:
    @searchTexts[$i] =~ s/^\s+//; @searchTexts[$i] =~ s/\s+$//; print @searchTexts[$i]."\n";
    ?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://786243]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (15)
As of 2015-03-05 16:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When putting a smiley right before a closing parenthesis, do you:









    Results (147 votes), past polls