2010-06-05 17 views
12

Posso fare qualcosa come il seguente in Perl?Posso tirare l'elemento successivo all'interno di un ciclo Foreach foreach?

foreach (@tokens) { 
    if (/foo/){ 
     # simple case, I can act on the current token alone 
     # do something 
     next; 
    } 
    if (/bar/) { 
     # now I need the next token, too 
     # I want to read/consume it, advancing the iterator, so that 
     # the next loop iteration will not also see it 
     my $nextToken = ..... 
     # do something 
     next; 
    } 

} 

Aggiornamento: Ho bisogno di questo in Perl, ma per curiosità: Do altre lingue hanno una sintassi pulito per questo?

risposta

19

È necessario utilizzare un ciclo for? Copiare l'originale e 'consumare' con shift:

use strict; 
use warnings; 

my @original = 'a' .. 'z'; # Original 
my @array = @original;  # Copy 

while (my $token = shift @array) { 

    shift @array if $token =~ /[nr]/; # consumes the next element 
    print $token; 
} 

# prints 'abcdefghijklmnpqrtuvwxyz' ('s' and 'o' are missing) 
+0

Bello. Nel mio caso, distruggere l'originale non è nemmeno un problema, quindi posso fare a meno della copia. – Thilo

8

Non con un ciclo foreach. È possibile utilizzare uno stile di C for ciclo:

for (my $i = 0; $i <= $#tokens; ++$i) { 
    local $_ = $tokens[$i]; 
    if (/foo/){ 
    next; 
    } 
    if (/bar/) { 
    my $nextToken = $tokens[++$i]; 
    # do something 
    next; 
    } 
} 

Si potrebbe anche usare qualcosa come Array::Iterator. Lascerò quella versione come un esercizio per il lettore. :-)

9

A partire da Perl 5.12, each is now more flexible lavorando anche su array:

use 5.012; 
use warnings; 

my @tokens = 'a' .. 'z'; 

while (my ($i, $val) = each @tokens) { 
    if ($val =~ m/[aeiou]/) { 
     ($i, $val) = each @tokens; # get next token after a vowel 
     print $val; 
    } 
} 

# => bfjpv 


Un avvertimento con each, ricorda l'iteratore è globale e non viene ripristinato se si interrompe il ciclo.

Per esempio:

while (my ($i, $val) = each @tokens) { 
    print $val; 
    last if $i == 12; 
} 

# => abcdefghijklm 

my ($i, $val) = each @tokens; 
say "Now at => $val ($i)";   # Now at => n (13) 

usa keys o values per ripristinare manualmente all'iteratore:

keys @tokens;      # resets iterator 
($i, $val) = each @tokens; 
say "Now at => $val ($i)";   # Now at => a (0) 
+0

Whoa! Non lo sapevo - questo tornerà utile. Grazie :) – zdim

0

mi piace Zaids risposta, ma viene a mancare se incontra un elemento nul nella matrice così ...

while (@array) { 

    my $token = shift @array; 
    shift @array if $token =~ /[nr]/; # consumes the next element 
    print $token; 
} 

questo non lo sto p fino a @array è vuoto.