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

I'm not clear if foreach empties the array, or does while do that or both - or neither?
  • Comment on how do foreach and while affect an array?

Replies are listed 'Best First'.
Re: how do foreach and while affect an array?
by davido (Cardinal) on Sep 12, 2004 at 16:59 UTC

    Neither foreach nor while implicitly empty arrays. I recommend reading through both perlintro, and then perlsyn to understand Perl's looping constructs better. Particularly, perlsyn give a detailed discussion of Perl's looping mechanisms.

    If the behavior you're after is to empty an array, you can use shift or pop to remove one element at a time in a loop, like this:

    while ( @array ) { my $element = shift @array; # or "my $element = pop @array;". # Now, do something with $element }

    Loops just loop, that's all they do. In the case of for or foreach, they iterate over a list (or an array). In the case of while, they loop until a test condition is false. In the case of until, they loop until a test condition is true.

    In the case of foreach ( @array ) loops, while the loop itself is non-destructive, the special variable $_ is aliased to each element in the array, one by one as foreach iterates over the array (or list). This means that if you modify $_, the effect will ripple back into the array over which you're iterating, so be careful. This also applies to the iterator variable in foreach loops, even if a named iterator is declared, eg. "foreach my $element ( @array ) {....". Also note that it is almost always a bad idea to add or remove elements from an array while looping over it via foreach as it leads to ambiguity such as "are you looping over the newly resized array, or the original?"


    Dave

Re: how do foreach and while affect an array?
by ikegami (Pope) on Sep 12, 2004 at 17:13 UTC

    Neither foreach (aka for), while nor do..while change the contents. But what's in the these loops can.

    If you modify the variable of foreach (or $_ if a variable isn't specified) as shown in the following code, it will affect that element of the array. This is done very commonly.

    @a = qw( food foot ); foreach (@a) { s/foo/bar/g } # @a is now qw( bard bart )

    The following is a example of a strategy sometimes used with while:

    sub visit_breadth_first { my ($node, $visitor) = @_; # Initial value: my @to_visit = ($node); # Loop as long as @to_visit isn't empty: while (@to_visit) { # Remove an element: my $current = shift(@to_visit); # Maybe add some elements: push(@to_visit, @{$current->children()}); &$visitor($current); } }

    In case you're looking for ways to modify the array, look at map, grep and sort. If you assign the value they return back to the original array, it's going to be modified. For example:

    @a = map { ... transformation ... } @a; @a = grep { ... filter ... } @a; @a = sort { ... equiv test ... } @a;
Re: how do foreach and while affect an array?
by jbware (Chaplain) on Sep 12, 2004 at 16:57 UTC
    foreach is nondestructive.

    Update I just reread that question. Both foreach and while are nondestructive. You can iterate through arrays using foreach and while w/o worrying about losing data.

    -jbWare
      You can iterate through arrays using foreach and while w/o worrying about losing data.

      Yes, foreach() ( aka for() ) does iterate through the array, and it does not affect the contents of the array on its own. But just to be clear, one doesn't iterate through arrays with while().

      while() can indeed be utilized to run through an array, but whether that affects the contents of the array depends on the implementation. In the end, while() does not operate on arrays on its own in any fashion.

      Zenon Zabinski | zdog | zdog@perlmonk.org

Re: how do foreach and while affect an array?
by superfrink (Curate) on Sep 12, 2004 at 16:58 UTC
    Looping over an array does not actually change it's contents (as far as I know, maybe there are some special arrays).
    use Data::Dumper; @arr = (1,2,3); print Dumper(\@arr); foreach $i (@arr) { # not doing or changing anything here. } print Dumper(\@arr);
    Shows that the array contents have not been changed. The same should hold for while loops.

    Update: I guess I will mention that in PHP there are loop counters that you sometimes have to reset each time you want to iterate over an array. I don't know of anything like that in Perl though. Maybe that's where this question came from.
Re: how do foreach and while affect an array?
by ysth (Canon) on Sep 12, 2004 at 19:04 UTC
    Neither. Here is an idiom I occasionally use that does empty an array, though:
    my $width = 4; my @in = "a".."z"; while (my @row = splice(@in, 0, $width)) { print "@row\n"; } __END__ Output: a b c d e f g h i j k l m n o p q r s t u v w x y z
Re: how do foreach and while affect an array?
by Anonymous Monk on Sep 13, 2004 at 11:33 UTC
    Well, that entirely depends on how you use foreach and while to iterate over the array. If you do something like: foreach ($a = @a; $a --;) {local $a = shift(@a); ...}, the array is being destroyed. But if you do $a = 0; while ($a < @a) {...; $a++}, the array isn't destroyed.