2009-06-10 10 views
64

Wenn ich die folgende Anordnung in Perl haben:automatisch Schleifenindex in foreach Schleife in Perl erhalten

@x = qw(a b c); 

und I iterieren mit foreach, dann $_ dem aktuellen Element im Array beziehen:

foreach (@x) { 
    print; 
} 

druckt:

abc 

Gibt es einen ähnlichen Weg, den Index des aktuellen Elements zu erhalten, ohne einen Zähler manuell zu aktualisieren? Etwas wie:

foreach (@x) { 
    print $index; 
} 

wo $index wie $_ aktualisiert wird, um die Ausgabe zu erhalten:

012 

Antwort

95

Wie Codehead sagte, müssten Sie über die Array-Indizes statt seiner Elemente iterieren. Ich bevorzuge diese Variante gegenüber dem C-Stil für die Schleife:

for my $i (0 .. $#x) { 
    print "$i: $x[$i]\n"; 
} 
+13

+1 für die Verwendung der hässlichen C-style for-Schleife. – fengshaun

+3

Dies ist nicht was Sie wollen, wenn Array-Index-Sequenz 2, 5, 8, 19 mit Lücken in der Sequenz ist. Ich glaube, dass die Frage etwas bezüglich des Index des aktuellen Elements war. – Andy

22

perldoc perlvar scheint keine solche Variable vorzuschlagen.

+15

+1 für einen Mann zu lehren, wie –

+6

zu fischen -1. Das widerspricht völlig dem Geist von Stackoverflow. – AndrewKS

+4

[* AndrewKS *] (http: // Stapelüberlauf.com/users/444794/andrewks): Dies ist sicherlich * nicht * gegen den Geist von StackOverflow. Wenn Sie "perldoc perlvar" probiert hätten, wüssten Sie warum. Es sind nur die in "perldoc perlvar" aufgeführten Variablen vorhanden. Eine solche Variable existiert nicht, wie ich bereits sagte. –

7

Nicht mit foreach. Wenn Sie die Elementkardinalität im Array unbedingt benötigen, verwenden Sie einen 'for' Iterator.

for($i=0;$i<@x;++$i) { 
    print "Element at index $i is ",$x[$i],"\n"; 
} 
+5

Foreach und For sind austauschbare Synonyme. Einige einleitende Materialien versuchen zu verwenden, um die C-Stil-Schleife und foreach für die Liste Iterator-Schleife zu bedeuten, aber die Verwendung der Terminologie wird nicht jedem bekannt sein. – ysth

+1

foreach und for sind/nicht/austauschbar, wie diese Instanz zeigt. –

+0

@Matthew Flaschen Es ist korrekter zu sagen, dass Sie das Schlüsselwort foreach durch das Schlüsselwort für, aber nicht unbedingt umgekehrt ersetzen können. –

4

Nein, Sie müssen Ihren eigenen Zähler machen. Ein weiteres Beispiel:

my $index; 
foreach (@x) { 
    print $index++; 
} 

wenn für die Indizierung

my $index; 
foreach (@x) { 
    print $x[$index]+$y[$index]; 
    $index++; 
} 

Und natürlich verwendet werden, können Sie local $index; statt my $index; und so und so verwenden.

BEARBEITEN: Aktualisiert nach dem ersten Kommentar der ysth.

+1

0+ ist nicht erforderlich; postincrement gibt 0 zurück, wenn die inkrementierte Variable undef ist. – ysth

+0

Sie brauchen dort nicht lokal. mein würde gut funktionieren. – ysth

+0

@ysth: Sie können überrascht sein, wenn jemand irgendwo in der Anwendung dieselbe globale $ index Variable wie Sie verwendet. Aber wenn Sie ein kurzes Skript schreiben und Sie annehmen ... nein, tun Sie es nicht. –

0

Nun gibt es auf diese Weise:

use List::Rubyish; 

$list = List::Rubyish->new([ qw<a b c> ]); 
$list->each_index(sub { say "\$_=$_" }); 

siehe List::Rubyish

39

In Perl vor 5.10, Sie

#!/usr/bin/perl 

use strict; 
use warnings; 

my @a = qw/a b c d e/; 

my $index; 
for my $elem (@a) { 
    print "At index ", $index++, ", I saw $elem\n"; 
} 

#or 

for my $index (0 .. $#a) { 
    print "At index $index I saw $a[$elem]\n"; 
}  

In Perl 5.10 sagen, Sie state verwenden, um eine Variable zu deklarieren das wird nie neu initialisiert (im Gegensatz zu denen, die mit erstellt werden). Auf diese Weise können Sie die $index Variable in einem kleineren Umfang zu halten, aber zu Fehlern führen können (wenn Sie die Schleife ein zweites Mal eingeben, wird es immer noch den letzten Wert hat):

#!/usr/bin/perl 

use 5.010; 
use strict; 
use warnings; 

my @a = qw/a b c d e/; 

for my $elem (@a) { 
    state $index; 
    say "At index ", $index++, ", I saw $elem"; 
} 

In Perl 5.12 kann man sagen,

#!/usr/bin/perl 

use 5.012; #this enables strict 
use warnings; 

my @a = qw/a b c d e/; 

while (my ($index, $elem) = each @a) { 
    say "At index $index I saw $elem"; 
} 

Aber seien Sie gewarnt: Sie gibt es restrictions zu dem, was Sie berechtigt sind, mit @a zu tun, während über ihm mit each iterieren.

Es wird Sie jetzt nicht helfen, aber in 6 Perl können Sie sagen

#!/usr/bin/perl6 

my @a = <a b c d e>; 
for @a Z 0 .. Inf -> $elem, $index { 
    say "at index $index, I saw $elem" 
} 

Der Z Betreiber zusammen die beiden Listen Reißverschlüsse (dh es dauert ein Element aus der ersten Liste, dann ein Element von der Sekunde, dann ein Element von der ersten, und so weiter). Die zweite Liste ist eine lazy Liste, die jede ganze Zahl von 0 bis unendlich (zumindest theoretisch) enthält. Die -> $elem, $index sagt, dass wir aus dem Ergebnis der ZIP zwei Werte auf einmal nehmen. Der Rest sollte normal für Sie aussehen (es sei denn, Sie sind nicht vertraut mit der Funktion von 5.10 noch).

+0

Ich mag den Abschnitt über 'state' nicht, ich denke, es wäre besser mit' {my $ index; ...} '. –

+1

Großartig! Viel gelernt. –

0

Sie sollten nicht den Index in den meisten Fällen wissen müssen, können Sie diese

tun können
my @arr = (1, 2, 3); 
foreach (@arr) { 
    $_++; 
} 
print join(", ", @arr); 

In diesem Fall wäre der Ausgang 2 sein, 3, 4 als foreach einen Alias ​​zu den Sets tatsächliches Element, nicht nur eine Kopie.

+0

Was passiert, wenn Sie die erste Zeile ersetzen mit: meine @arr = ('foo', 'bar', 'foo'); – Anon

+0

Es würde 1, 1, 1 drucken, da String-Skalare bei Verwendung im Zahlenkontext auf Null ausgewertet werden. –

+4

Ich weiß, dass ich den Index in den meisten Fällen nicht benötige. Die Frage ist der beste Weg, um es zu bekommen, wenn ich es brauche. –

1

autobox::Core bietet unter vielen anderen Dingen eine praktische for Methode:

use autobox::Core; 

['a'..'z']->for(sub{ 
    my ($index, $value) = @_; 
    say "$index => $value"; 
}); 

Alternativ einen Blick auf einer Iterator-Modul hat, zum Beispiel: Array::Iterator

use Array::Iterator; 

my $iter = Array::Iterator->new(['a'..'z']); 
while ($iter->hasNext) { 
    $iter->getNext; 
    say $iter->currentIndex . ' => ' . $iter->current; 
} 

Siehe auch:

/I3az/

+0

Ich würde die Links zu den Distributionen mit einem Link der Form ersetzen: http://search.cpan.org/perldoc/Array::Iterator –

+0

@Brad Gilbert: Geändert. Obwohl ich persönlich die von (http://search.cpan.org/dist/Array-Iterator) – draegtun

+0

präsentierte Top-Level-Ansicht (Home) bevorzuge, würde ich zustimmen, dass es manchmal nützlich ist, auf die Dist-Ansicht anstatt auf die Perldoc-Ansicht zu zeigen. Auch nur weil ich * die Links ersetzen würde, heißt das nicht unbedingt, dass Sie * sollten *. –

0

Ich habe versucht, wie ....

@array = qw /tomato banana papaya potato/;     # example array 
my $count;             # local variable initial value will be 0 
print "\nBefore For loop value of counter is $count";  # just printing value before entering in loop 

for (@array) { print "\n",$count++," $_" ; }    # string and variable seperated by comma to 
                  # execute the value and print 
undef $count;            # undefining so that later parts again it will 
                  # be reset to 0 

print "\nAfter for loop value of counter is $count";  # checking the counter value after for loop. 

kurz ..

@array = qw /a b c d/; 
my $count; 
for (@array) { print "\n",$count++," $_"; } 
undef $count; 
+0

also im Grunde suggerieren Sie, dass ich den Index manuell nachverfolgen. –

4

Ja. Ich habe so viele Bücher und andere Blogs überprüft ... Fazit ist, es gibt keine Systemvariable für den Schleifenzähler. wir müssen unseren eigenen Zähler machen. korrigiere mich wenn ich falsch liege.

5

Perl Version 5.14.4

kann mit dem while Schleife durchgeführt werden (foreach dies nicht unterstützt)

my @arr = (1111, 2222, 3333); 

while (my ($index, $element) = each(@arr)) 
{ 
    # You may need to "use feature 'say';" 
    say "Index: $index, Element: $element"; 
} 

Ausgang:

Index: 0, Element: 1111 
Index: 1, Element: 2222 
Index: 2, Element: 3333