views:

126

answers:

4

Does Perl's foreach loop operator require that the list items be presented in order?

For example

my @a=(1,2,3);

foreach my $item (@a) {
 print $item;
}

will always print 1 2 3?

I suspect so, but I can't find it documented.

+3  A: 

Yes, it will. Arrays and lists are ordered.

David Dorward
+10  A: 

Yes. It iterates in the list order. as far as it being documented, look at perldoc perlsyn:

The foreach loop iterates over a normal list value and sets the variable VAR to be each element of the list in turn.

"In turn" here means in order.

DVK
Be aware also that the order of keys in a hash is undefined and not ordered. Lists are always ordered in any place they are used.
Daenyth
not just undefined, but explicitly randomized in recent versions of perl for increased security
Eric Strom
@Eric I'll bite: what's the security concern?
Telemachus
@Telemachus => see Algorithmic Complexity Attacks in perlsec - http://search.cpan.org/perldoc?perlsec.
Eric Strom
+3  A: 

Yes, arrays preserve order, while hashes do not.

kemp
+3  A: 

Yes.

Some apparent complexity (arrays are in order, but hashes are not--WTF?) comes from the fact that most answers are ignoring the importance of context.

Perl variables, functions, operators and subroutines may evaluate to different values depending on context. Context can either be scalar or list.

In scalar context, we want only one value. For example my $count = @array; assigns the number of elements in @array to $count, because assignment to a scalar provides a scalar context.

In list context we are looking for multiple values. For example, my @merged = @left, @right;. Assignment to an array provides list context, so @left and @right are expanded into a lists of their elements. Since lists are flat structures, we have one long list that combines elements from both arrays. Finally, the list of values is assigned to @merged.

The reason that most of the answers gloss over this is that, even though context seems strange at first, 99% of the time context works transparently and does what you'd expect.

The for loop provides a list context. This means that whatever is inside the parenthesis is interpreted in list context. The resulting list is then iterated over in order.

What this means is that:

  • for (@array) {} expands the array into list of elements, preserving the order of the array.
  • for (%hash) {} expands the hash into a random ordered list of key/value pairs.
  • for ( <FILEHANDLE> ) {} reads all the lines available from the filehandle and presents them in order.
  • for ( some_subroutine() ) {} evaluates some_subroutine() in list context and iterates over the results.
daotoad