38 votes

Comment lire deux éléments à la fois dans une boucle Perl foreach?

Ce que je recherche, c'est quelque chose comme:

 @list = qw(1 2 3 4 5 6);
foreach (@list) {
  #perl magic goes here 
  print "i: $i, j:$j\n";
}
 

Retour:

 i:1, j:2
i:3, j:4
i:5, j:6
 

En réponse à une très bonne suggestion ci-dessous, je dois spécifier que ce script s'exécutera sur le serveur de build de quelqu'un d'autre, et je ne suis pas autorisé à utiliser les modules du CPAN. Perl standard uniquement.

41voto

mirod Points 10845

Je crois que la bonne façon de le faire est d'utiliser natatime, de la Liste::MoreUtils:

à partir de la documentation:

natatime de la LISTE de blocage

Crée un tableau d'itérateur, pour boucler sur un éventail de morceaux de $narticles à une époque. (n à un moment, l'obtenir?). Un exemple en est probablement une meilleure l'explication que j'ai pu donner dans les mots.

Exemple:

 my @x = ('a' .. 'g');
 my $it = natatime 3, @x;
 while (my @vals = $it->())
 {
     print "@vals\n";
 }

Cette affiche

a b c
d e f
g

La mise en œuvre de l' List::MoreUtils::natatime:

sub natatime ($@)
{
    my $n = shift;
    my @list = @_;

    return sub
    {
        return splice @list, 0, $n;
    }
}

21voto

Andrew Barnett Points 2324

J'utiliserais une épissure.

 my @list = qw(1 2 3 4 5 6);
while(my ($i,$j) = splice(@list,0,2)) {
  print "i: $i, j: $j\n";
}
 

18voto

Jack M. Points 8224

Je pense que vous voudriez faire cela différemment. Essaye ça:

 while (scalar(@list) > 0) {
    $i = shift(@list);
    $j = shift(@list);
    print "i: $i, j:$j\n";
}
 

Gardez à l'esprit que cela détruira la liste, mais cela fonctionnera pour cette petite boucle.

16voto

Brad Gilbert Points 12724

Définir des données de test, et de les importer say:

use Modern::Perl;
use List::AllUtils qw'zip';

my @array = zip @{['a'..'z']}, @{[1..26]} ;

Simple boucle à l'aide d'un incrément de la variable.

    {
      my $i = 0;
      while(
        (my($a,$b) = @array[$i++,$i++]),
        $i <= @array # boolean test
      ){
        say "$a => $b";
      }
    }

Boucler sur les paires en utilisant List::Pairwise (pair).

    use List::Pairwise qw'pair';

    for my $pair (pair @array){
      my($a,$b) = @$pair;

      say "$a => $b";
    }

Boucler sur l'ensemble 2 à la fois, à l'aide de List::MoreUtils (natatime).

    use List::AllUtils qw'natatime';

    my $iter = natatime 2, @array;
    while( my($a,$b) = $iter->() ){
      say "$a => $b";
    }

Forcer dans une table de hachage, et en boucle sur les touches. Utile si vous n'avez pas de soins sur l'ordre.

    {
      my %map = @array;
      for my $key (keys %map){
        my $value = $map{$key};
        say "$key => $value";
      }
    }

11voto

chaos Points 69029

L'équivalent le plus proche est malheureusement le passage à la vieille école:

 for(my $ix = 0; $ix <= $#list; $ix += 2) {
    my $i = $list[$ix];
    my $j = $list[$ix + 1];
    print "i: $i, j:$j\n";
}
 

J'aime mieux la réponse de Jack M, bien que je l'écrirais en Perl plus sexy:

 while(@list) {
    my $i = shift @list;
    my $j = shift @list;
    print "i: $i, j:$j\n";
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X