69 votes

Perl: if (élément dans la liste)

Je recherche la présence d'un élément dans une liste.

En Python, il existe un mot clé in et je ferais quelque chose comme:

 if element in list:
    doTask
 

Y at-il quelque chose d’équivalent dans Perl sans avoir à parcourir manuellement la liste entière?

111voto

Brad Gilbert Points 12724

Si vous pouvez sortir à la nécessité de Perl v5.10, alors vous pouvez utiliser l'un des exemples suivants.

  • La correspondance intelligent ~~ de l'opérateur.

    if( $element ~~ @list ){ ... }
    if( $element ~~ [ 1, 2, 3 ] ){ ... }
    
  • Vous pouvez également utiliser l' given/when construire. Qui utilise le smart match de la fonctionnalité à l'interne.

    given( $element ){
       when( @list ){ ... }
    }
    
  • Vous pouvez également utiliser un for boucle comme un "topicalizer" ( ce qui signifie qu'il définit $_ ).

    for( @elements ){
       when( @list ){ ... }
    }
    

Une chose qui va sortir en Perl 5.12 est la capacité à utiliser le post-fix version de when. Ce qui rend encore plus comme if et unless.

given( $element ){
  ... when @list;
}

Si vous avez d'être en mesure de fonctionner sur d'anciennes versions de Perl, il y a toujours plusieurs options.

  • Vous pourriez penser que vous pouvez vous en sortir avec l'aide de List::Util::tout d'abord, mais il y a certaines conditions de bords qui rendent problématique.

    Dans cet exemple, il est assez évident que nous voulons réussir match contre 0. Malheureusement, ce code affichera failure à chaque fois.

    use List::Util qw'first';
    my $element = 0;
    if( first { $element eq $_ } 0..9 ){
      print "success\n";
    } else {
      print "failure\n";
    }
    

    Vous pouvez vérifier la valeur de retour de l' first pour la défini-tion, mais qui ne manquera pas, si nous voulons effectivement un match contre undef pour réussir.

  • Vous pouvez utiliser en toute sécurité grep cependant.

    if( grep { $element eq $_ } 0..9 ){ ... }
    

    C'est sûr, parce qu' grep est appelée dans un contexte scalaire. Les tableaux de retourner le nombre d'éléments lorsqu'elle est appelée dans un contexte scalaire. Ce qui permettra de continuer à travailler même si nous essayons de faire correspondre undef.

  • Vous pouvez utiliser un enfermant for boucle. Juste assurez-vous vous appelez last, à la sortie de la boucle sur un match de succès. Sinon, vous pourriez finir vers le haut de l'exécution de votre code plus d'une fois.

    for( @array ){
      if( $element eq $_ ){
        ...
        last;
      }
    }
    
  • Vous pourriez mettre la for boucle à l'intérieur de l'état de l' if déclaration ...

    if(
      do{
        my $match = 0;
        for( @list ){
          if( $element eq $_ ){
            $match = 1;
            last;
          }
        }
        $match; # the return value of the do block
      }
    ){
      ...
    }
    
  • ... mais il serait peut-être plus clair pour mettre la for boucle avant de l' if déclaration.

    my $match = 0;
    for( @list ){
      if( $_ eq $element ){
        $match = 1;
        last;
      }
    }
    
    if( $match ){ ... }
    
  • Si vous êtes seulement le rapprochement avec des chaînes, vous pouvez également utiliser une table de hachage. Cela peut accélérer la vitesse de votre programme si @list est grande et la, vous allez match contre %hash plusieurs fois. Surtout si @array ne change pas, parce que vous n'avez plus qu'à charger, %hash une fois.

    my %hash = map { $_, 1 } @array;
    if( $hash{ $element } ){ ... }
    
  • Vous pouvez également faire votre propre sous-routine. C'est un des cas où il est utile d'utiliser des prototypes.

    sub in(&@){
      local $_;
      my $code = shift;
      for( @_ ){ # sets $_
        if( $code->() ){
          return 1;
        }
      }
      return 0;
    }
    
    if( in { $element eq $_ } @list ){ ... }
    

15voto

jrockway Points 23734
 if( $element ~~ @list ){
   do_task
}
 

~~ est l '"opérateur de correspondance intelligente" et ne se limite pas à la détection de la liste des membres.

9voto

DVK Points 63282

Liste :: Util :: first

 $foo = first { ($_ && $_ eq "value" } @list;    # first defined value in @list
 

Ou pour les types de roulement à la main:

 my $is_in_list = 0;
foreach my $elem (@list) {
    if ($elem && $elem eq $value_to_find) {
        $is_in_list = 1;
        last;
    }
}
if ($is_in_list) {
   ...
 

Une version légèrement différente PEUT être un peu plus rapide sur de très longues listes:

 my $is_in_list = 0;
for (my $i = 0; i < scalar(@list); ++$i) {
    if ($list[i] && $list[i] eq $value_to_find) {
        $is_in_list = 1;
        last;
    }
}
if ($is_in_list) {
   ...
 

8voto

Sinan Ünür Points 76179

Si vous envisagez de le faire plusieurs fois, vous pouvez échanger de l'espace pour le temps de recherche:

 #!/usr/bin/perl

use strict; use warnings;

my @array = qw( one ten twenty one );
my %lookup = map { $_ => undef } @array;

for my $element ( qw( one two three ) ) {
    if ( exists $lookup{ $element }) {
        print "$element\n";
    }
}
 

en supposant que le nombre de fois où l'élément apparaît dans @array n'est pas important et que le contenu de @array est de simples scalaires.

5voto

mob Points 61524

grep est utile ici

 if (grep { $_ eq $element } @list) {
    ....
}
 

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