For loop aliasing AND changing an array within a loop.

For loop aliasing AND changing an array within a loop.

Post by Zeus Od » Fri, 24 Jan 2003 03:04:31



When you loop through an array


should not each array element be aliased into $_: if you change $_, you
also change the element? This is what I remembered. However, a problem I
just encountered shook this recollection.

I think I read somewhere that you should NOT delete array elements from
within a loop. However, the following works very well.

The problem is that the current directory (/tmp) can contain multiple
mosfet*.tar.gz archives and multiple mosfet* directories. The following


$x=0;

   # Remove each array element that is NOT a directory name
   # OR remove ":\s+" from the end of dir name.
   if ( s/^(.*):\s+$/$1/ ){

   } else {                 # shouldn't the substitution change both?


      redo;
   }
   $x++;

Quote:}

--------------------SECOND TRY-----------------------------

$x=0;

   unless( $dir[$x] =~ s/^(.*):\s+$/$1/ ){

      $_ = $dir[$x];
      redo;
   }
   $x++;
Quote:}

 
 
 

For loop aliasing AND changing an array within a loop.

Post by John W. Kra » Fri, 24 Jan 2003 07:10:34



> When you loop through an array


> should not each array element be aliased into $_: if you change $_, you
> also change the element?

Yes, that is correct.

Quote:> This is what I remembered. However, a problem I
> just encountered shook this recollection.

> I think I read somewhere that you should NOT delete array elements from
> within a loop. However, the following works very well.

I think that you are thinking of hashes.

Found in /usr/lib/perl5/5.6.0/pod/perlfaq4.pod
       What happens if I add or remove keys from a hash while
       iterating over it?

       Don't do that. :-)

> The problem is that the current directory (/tmp) can contain multiple
> mosfet*.tar.gz archives and multiple mosfet* directories. The following

> --------------------FIRST TRY------------------------------


You don't have to call ls and grep to do this:


> $x=0;

>    # Remove each array element that is NOT a directory name
>    # OR remove ":\s+" from the end of dir name.
>    if ( s/^(.*):\s+$/$1/ ){

>    } else {                 # shouldn't the substitution change both?

It does change both:

$ perl -e'



    s/^(.*):\s+$/$1/;
    }

'
mosfet-1.2.3.tar.gz mosfet-new:  
mosfet-1.2.3.tar.gz mosfet-new



>       redo;
>    }
>    $x++;
> }

> --------------------SECOND TRY-----------------------------

> $x=0;

>    unless( $dir[$x] =~ s/^(.*):\s+$/$1/ ){

>       $_ = $dir[$x];
>       redo;
>    }
>    $x++;
> }

According to your actual problem:

> The problem is that the current directory (/tmp) can contain multiple
> mosfet*.tar.gz archives and multiple mosfet* directories. The following




John
--
use Perl;
program
fulfillment

 
 
 

For loop aliasing AND changing an array within a loop.

Post by Paul Johns » Fri, 24 Jan 2003 07:23:35




> > I think I read somewhere that you should NOT delete array elements from
> > within a loop. However, the following works very well.

> I think that you are thinking of hashes.

 From perlsyn:

 If any part of LIST is an array, "foreach" will get very
 confused if you add or remove elements within the loop
 body, for example with "splice".   So don't do that.

--

http://www.pjcj.net

 
 
 

For loop aliasing AND changing an array within a loop.

Post by John W. Kra » Fri, 24 Jan 2003 08:26:04




> > I think that you are thinking of hashes.

>  From perlsyn:

>  If any part of LIST is an array, "foreach" will get very
>  confused if you add or remove elements within the loop
>  body, for example with "splice".   So don't do that.

Ok, thanks.  I grep'ed perlsyn for delete so I didn't find it but I knew
it was in there somewhere.  :-)

John
--
use Perl;
program
fulfillment

 
 
 

For loop aliasing AND changing an array within a loop.

Post by Michael Hoot » Sat, 25 Jan 2003 05:30:30


While stepping through the code I wrote, I distinctly noted that the
substitution on $_ did NOT affect the array and vice versa. If anyone
insists on adding or deleting elements of an array from within a loop, you
can ... you just have to update either $_ or what $_ is aliased to, like the
original code I posted.

Thanks, John, for reminding me of glob. It does exactly what I need. Perl
has so many parts, it is easy to forget many of them.

Thanks.

-----Original Message-----

Sent: Wednesday, January 22, 2003 5:24 PM
To: John W. Krahn


Subject: Re: For loop aliasing AND changing an array within a loop.



> > I think I read somewhere that you should NOT delete array elements from
> > within a loop. However, the following works very well.

> I think that you are thinking of hashes.

 From perlsyn:

 If any part of LIST is an array, "foreach" will get very
 confused if you add or remove elements within the loop
 body, for example with "splice".   So don't do that.

--

http://www.pjcj.net

 
 
 

For loop aliasing AND changing an array within a loop.

Post by Rob Dix » Sun, 26 Jan 2003 02:38:00


Hi Michael.


> While stepping through the code I wrote, I distinctly noted that the
> substitution on $_ did NOT affect the array and vice versa.

If you watch carefully what Perl is doing, it aliases correctly _until_
you choose to modify the array. After this the correct value from
the original 'foreach' list is used, but aliasing is no longer
meaningful
and $_ is independent of the new array. It is effectively iterating
over a temporary copy of the original array.

Looking at your first algorithm:

> --------------------FIRST TRY------------------------------
> $x=0;

>    # Remove each array element that is NOT a directory name
>    # OR remove ":\s+" from the end of dir name.
>    if ( s/^(.*):\s+$/$1/ ){

>    } else {                 # shouldn't the substitution change both?


>       redo;
>    }
>    $x++;
> }

Since the assignment to $_ in your 'else' clause has no effect on the
execution, and because of your modification of the array within
the loop, the following code is equivalent:

    my $x=0;


        if ( $_ =~ s/^(.*):\s+$/$1/ ){
            $dir[$x] = $1;
            $x++;
        } else {

        }
    }


Similarly your second try:

> --------------------SECOND TRY-----------------------------

> $x=0;

>    unless( $dir[$x] =~ s/^(.*):\s+$/$1/ ){

>       $_ = $dir[$x];
>       redo;
>    }
>    $x++;
> }

is equivalent to this:

    my $x=0;


        unless ($dir[$x] =~ s/^(.*):\s+$/$1/) {

        } else {
            $x++;
        }
    }

In both cases you can see that the value of $_ is unnecessary, and
is used only in the first case as an implicit parameter to the
substitution operator. The second case may therefore be more
appropriately written as:

    my $x = 0;

        :
    }

since you are using 'foreach' only to execute the body of the loop
the correct number of times.

Quote:> If anyone insists on adding or deleting elements of an array from
> within a loop, you can ...

...expect to have problems. Remember that you are doing something
that perldoc itself explicitly says not to do. It is very unlikely that
you know better, and certainly what you are doing is unsupported.
Even if it appears that you have a work-around then it will not be
a general solution, and is likely not to withstand alterations to the
related code.

Gradu diverso, via una.

Cheers Michael, and happy Perling.

Rob

 
 
 

1. MSN POP3 Loop-de-loop

 Again....maybe they're checking how far they can push. I predict a mass exodus if they do.;)

--
J. Dennis Russell, Sr.
Microsoft MVP
Please note:
Sandi Hardmeier/Nemesis and Zane Thomas/Sum One are *real* Microsoft MVPs.
To reply via e-mail, replace $$ with ss and replace notmail.com
with hotmail.com

2. File Manger and Prog Manager Replacement

3. Loop d Loops

4. Net User Command on Win2K Server

5. gtk main loop and mico orb loop

6. Communication with Windows programs

7. % Loop limit expression too large for loop variable type.

8. Help on "15 hours FREE InterNet" deal

9. loop-d-loop

10. need a loop within a makefile

11. Executing Multiple procedures within one do-loop

12. methods for selective display within a loop