web-dev-qa-db-fra.com

récupère automatiquement l'index de boucle dans une boucle foreach en perl

Si j'ai le tableau suivant en Perl:

@x = qw(a b c);

et j'itère dessus avec foreach, alors $_ fera référence à l'élément actuel du tableau:

foreach (@x) {
    print;
}

imprimera:

abc

Existe-t-il un moyen similaire d’obtenir le index de l’élément en cours sans mettre à jour manuellement un compteur? Quelque chose comme:

foreach (@x) {
    print $index;
}

$index est mis à jour comme $_ pour générer le résultat:

012
70
Nathan Fellman

Comme dit Codehead, il vous faudrait parcourir les index du tableau plutôt que ses éléments. Je préfère cette variante au style C pour la boucle:

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

En Perl avant 5.10, vous pouvez dire

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

Dans Perl 5.10, vous utilisez tat pour déclarer une variable qui ne sera jamais réinitialisée (contrairement à ceux créés avec my ). Cela vous permet de conserver la variable $index dans une portée plus petite, mais peut entraîner des bugs (si vous entrez la boucle une seconde fois, elle aura toujours la dernière valeur):

#!/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, vous pouvez dire

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

Mais soyez averti: vous avez des restrictions à ce que vous êtes autorisé à faire avec @a tout en itérant dessus avec each.

Cela ne vous aidera pas maintenant, mais dans Perl 6, vous pourrez dire

#!/usr/bin/Perl6

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

L’opérateur Z compresse les deux listes ensemble (c’est-à-dire qu’il prend un élément de la première liste, puis un élément de la seconde, puis un élément de la première, etc.). La deuxième liste est une liste lazy qui contient tous les entiers de 0 à l’infini (au moins théoriquement). Le -> $elem, $index indique que nous prenons deux valeurs à la fois du résultat du zip. Le reste devrait vous paraître normal (sauf si vous n'êtes pas encore familiarisé avec la fonction say de 5.10).

42
Chas. Owens

perldoc perlvar ne semble pas suggérer une telle variable.

23
Alan Haggai Alavi

Pas avec foreach . Si vous avez vraiment besoin de la cardinalité des éléments du tableau, utilisez un itérateur 'pour'.

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

Version Perl 5.14.4

Peut être fait avec la boucle while (foreach ne le supporte pas)

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

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

Sortie:

Index: 0, Element: 1111
Index: 1, Element: 2222
Index: 2, Element: 3333
5
Venkata Raju

Oui. J'ai vérifié tellement de livres et d'autres blogs ... En conclusion, il n'y a pas de variable système pour le compteur de boucles. nous devons faire notre propre comptoir. Corrige moi si je me trompe.

4
surendra ben

Non, vous devez faire votre propre comptoir. Encore un autre exemple:

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

lorsqu'il est utilisé pour l'indexation

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

Et bien sûr, vous pouvez utiliser local $index; à la place de my $index; et ainsi de suite.

EDIT: Mis à jour en fonction du commentaire du premier ysth.

4

autobox::Core fournit, parmi beaucoup d'autres choses, une méthode pratique for:

use autobox::Core;

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

Vous pouvez également consulter un module itérateur, par exemple: Array::Iterator

use Array::Iterator;

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

Regarde aussi:

/ I3az /

2
draegtun

Eh bien, voici comment: 

use List::Rubyish;

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

voir Liste :: Rubyish

1
Axeman

Oh oui tu peux! (en quelque sorte, mais vous ne devriez pas). each(@array) dans un contexte scalaire vous donne l'index actuel du tableau.

@a = (a..z);
for (@a){ 
  print each(@a) . "\t" . $_ . "\n"; 
}

Ici, each(@a) se trouve dans un contexte scalaire et renvoie uniquement l'index, pas la valeur de cet index. Puisque nous sommes dans une boucle for, nous avons déjà la valeur dans $ _. Le même mécanisme est souvent utilisé dans une boucle While-Each. Même problème.

Le problème vient si vous refaites for(@a), l'index n'est pas remis à 0 comme prévu, c'est undef suivi de 0,1,2 ... un décompte. Le perldoc de each() indique que pour éviter ce problème, utilisez une boucle for pour suivre l'index. https://perldoc.Perl.org/functions/each.html

Fondamentalement:

for(my $i=0; $i<=$#a; $i++){
  print "The Element at $i is $a[$i]\n";
}

Je suis fan de la méthode alternative:

my $index=0;
for (@a){
  print "The Element at $index is $a[$index]\n";
  $index++;
}
1
Able Mac

J'ai essayé comme ...

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

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

Veuillez considérer: 

print "Element at index $_ is $x[$_]\n" for keys @x;
0
aaa

Vous ne devriez pas avoir besoin de connaître l'index dans la plupart des cas, vous pouvez le faire

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

Dans ce cas, la sortie serait 2, 3, 4 car foreach définit un alias sur l'élément réel, pas seulement une copie.

0
anonymous coward