2012-10-17 15 views
5

ho appena cominciato a imparare Perl e mi sono ritrovato ostacolati dal risultato della seguente blocco di codice:Comportamento di 'foreach' in Perl

@x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 
foreach (@x) { 
    $x = pop (@x) ; 
    $y = shift (@x); 
    print ("$x $y \n"); 
} 

L'output è:

10 1 
9 2 
8 3 
7 4 

I mi aspettavo un'altra linea: 6 5. Perché non c'è una tale linea? È perché dopo l'iterazione che stampa 7 4, il numero di elementi rimasti nella matrice è uguale al numero di iterazioni già completate, e quindi per quanto riguarda Perl, il ciclo è finito?

risposta

8

Probabilmente non è necessario modificare l'elenco durante l'iterazione. Da perldoc perlsyn:

Se una qualsiasi parte del LIST è un array, foreach otterrà molto confuso se si aggiungono o rimuovono gli elementi all'interno del corpo del ciclo, ad esempio con splice. Quindi non farlo.

Se si stampa $_ durante il ciclo (print ("$x $y $_\n");), si può vedere cosa sta succedendo:

10 1 1 
9 2 3 
8 3 5 
7 4 7 

In questo caso Perl è solo il mantenimento di un indice che incrementa attraverso l'array. Poiché si eliminano gli elementi dall'inizio, l'indice cade dalla fine dell'array modificato alla fine della quarta iterazione e quindi il ciclo foreach termina.

+0

Grazie nneonneo. La tua spiegazione di ciò che accade era esattamente ciò che dovevo capire. – verbose

7

Questa è una buona illustrazione di cosa succede quando si modifica la matrice su cui si sta iterando.

Prova:

use strict: #Always! 
use warnings; #Always! 

my @x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 
my $n=$#x; 
foreach my $i(0..$n) { 
    my $x = pop (@x) ; 
    my $y = shift (@x); 
    print "$x $y\n" if defined $x and defined $y; 
} 

O, meglio ancora:

use strict; 
use warnings; 

my @x=1..10; #same thing, just written more idiomatically 

while(@x) 
{ 
    my $x=pop @x; #no parentheses needed 
    my $y=shift @x; 
    print "$x $y\n"; 
} 

Nota in while ciclo precedente, la matrice @x è essere interpreted in scalar context, quindi il ciclo while continuerà fino a quando il numero di elementi in @x è zero.

3

Non è consentito modificare l'array su cui si sta iterando utilizzando un ciclo foreach.

Non si desidera eseguire iterazioni sugli elementi dell'array in ogni caso. foreach (@x) è chiaramente sbagliato. Questo ciclo si ripete 10 volte, ma si desidera eseguire il ciclo solo 5 volte.

Poiché si rimuovono gli elementi dall'array mentre si esegue il ciclo, è sufficiente eseguire il ciclo finché l'array non è vuoto. Per verificare una condizione ad ogni passaggio del ciclo, si usa un ciclo while.

my @x = 1..10; 
while (@x) { 
    my $x = pop(@x) ; 
    my $y = shift(@x); 
    print("$x $y\n"); 
} 

Se si voleva utilizzare un ciclo foreach, sarebbe simile a questa:

my @x = 1..10; 
for ([email protected]/2) { 
    my $x = $x[-$_]; 
    my $y = $x[$_-1]; 
    print("$x $y\n"); 
}