2009-06-10 22 views
64

Si tengo la siguiente matriz en Perl:consigue automáticamente índice del bucle en el bucle foreach en Perl

@x = qw(a b c); 

y yo iterar sobre con foreach, entonces $_ se referirá a la elemento actual en la matriz:

foreach (@x) { 
    print; 
} 

imprimirá:

abc 

¿Hay alguna manera similar de obtener el índice del elemento actual, sin actualizar manualmente un contador? Algo como:

foreach (@x) { 
    print $index; 
} 

donde $index se actualiza como $_ para producir la salida:

012 

Respuesta

95

Como dijo codehead, tendrías que iterar sobre los índices de matriz en lugar de sus elementos. Prefiero esta variante sobre el C-style for loop:

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

+1 por no usar el feo C-style for-loop. – fengshaun

+3

Esto no es lo que desea si la secuencia de índice de matriz es 2, 5, 8, 19 con huecos en secuencia. Creo que la pregunta era sobre el índice del elemento actual. – Andy

22

perldoc perlvar no parece sugerir cualquier variable.

+15

+1 para enseñar a un hombre a pescar –

+6

-1. Esto va totalmente en contra del espíritu de Stackoverflow. – AndrewKS

+4

[* AndrewKS *] (http: // stackoverflow.com/users/444794/andrewks): Esto ciertamente * no * está en contra del espíritu de StackOverflow. Si hubiera intentado 'perldoc perlvar', sabría por qué. Solo existen las variables listadas en 'perldoc perlvar'. Tal variable, como ya dije, no existe. –

7

No con foreach. Si definitivamente necesita la cardinalidad del elemento en la matriz, use un iterador 'for'.

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

foreach y for son sinónimos intercambiables. Algunos materiales introductorios intentan usar para significar el bucle de estilo C y foreach para el bucle del iterador de lista, pero ese uso de la terminología no va a ser familiar para todos. – ysth

+1

foreach y para son/no/intercambiables, como muestra esta instancia. –

+0

@Matthew Flaschen Es más correcto decir que puede reemplazar la palabra clave foreach por la palabra clave for, pero no necesariamente al revés. –

4

No, debes hacer tu propio contador. Otro ejemplo más:

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

cuando se utiliza para la indexación

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

Y, por supuesto, se puede utilizar en lugar local $index;my $index; y tal y tal.

EDIT: Actualizado según el comentario del primer ysth.

+1

0+ es innecesario; postincrement devuelve 0 si la variable incrementada fue undef. – ysth

+0

No necesita local allí. mi funcionaria bien – ysth

+0

@ysth: puede sorprenderse que alguien en algún lugar de la aplicación use la misma variable de índice $ global que usted. Pero si escribes un guión corto y asumes ... no, no lo hagas. –

0

Bueno hay esta manera:

use List::Rubyish; 

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

ver List::Rubyish

39

En Perl antes de la 5.10, se puede decir

#!/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"; 
}  

En Perl 5.10, se utiliza state para declarar una variable que nunca se reinicializa (a diferencia de los que se crean con my). Esto le permite mantener la variable $index en un ámbito más pequeño, pero puede dar lugar a errores (si introduce el bucle por segunda vez todavía tendrá el último valor):

#!/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"; 
} 

En Perl 5.12 se puede decir

#!/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"; 
} 

Pero cuidado: hay que restrictions a lo que se le permite ver con @a al iterar sobre ella con each.

No te va a ayudar ahora, pero en Perl 6 que va a ser capaz de decir

#!/usr/bin/perl6 

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

El operador Z cremalleras las dos listas (es decir que se necesita un elemento de la primera lista, entonces uno elemento del segundo, luego un elemento del primero, y así sucesivamente). La segunda lista es una lista lazy que contiene todos los números enteros desde 0 hasta infinito (al menos teóricamente). El -> $elem, $index dice que estamos tomando dos valores a la vez del resultado del zip. El resto debería parecerle normal (a menos que aún no esté familiarizado con la función say de 5.10).

+0

No me gusta la sección sobre 'estado', creo que sería mejor si' {my $ index; ...} '. –

+1

¡Genial! Aprendió mucho. –

0

No debería ser necesario conocer el índice en la mayoría de las circunstancias, se puede hacer esto

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

En este caso, la salida sería 2, 3, 4 como foreach establece un alias para el elemento real, no solo una copia.

+0

¿Qué pasaría si reemplaza la primera línea con: my @arr = ('foo', 'bar', 'foo'); – Anon

+0

Imprimirá 1, 1, 1 ya que los escalares de cadena se evalúan a cero cuando se usan en contexto numérico. –

+4

Sé que no necesito el índice en la mayoría de las circunstancias. La pregunta es sobre la mejor manera de obtenerlo cuando lo necesito. –

1

autobox::Core proporciona, entre muchas cosas más un práctico for método:

use autobox::Core; 

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

Alternativamente echar un vistazo a un módulo repetidor, por ejemplo: Array::Iterator

use Array::Iterator; 

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

Véase también:

/I3az/

+0

Reemplazaría los enlaces a las distribuciones con un enlace del formulario: http://search.cpan.org/perldoc/Array::Iterator –

+0

@Brad Gilbert: Modificado. Aunque personalmente prefiero la vista de nivel superior (inicio) presentada por http://search.cpan.org/dist/Array-Iterator – draegtun

+0

Estoy de acuerdo en que a veces es útil señalar la vista Dist en lugar de la vista perldoc. Además, solo porque * reemplace * los enlaces, no significa necesariamente que * deba *. –

0

he tratado como ....

@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. 

en fin ..

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

por lo que básicamente está sugiriendo que haga un seguimiento del índice manualmente. –

4

Sí. He revisado tantos libros y otros blogs ... la conclusión es que no existe una variable de sistema para el contador de bucles. tenemos que hacer nuestro propio contador. Corrígeme si estoy equivocado.

5

Perl versión 5.14.4

puede hacer con while bucle (foreach no soporta esta)

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

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

Salida:

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