2010-07-15 4 views
5

Je dois parcourir un tableau et supprimer des éléments de manière conditionnelle, en Perl. Je connais environ slice, mais je ne sais pas comment l'utiliser dans un contexte foreach.L'équivalent Perl de `rejeter! 'De Ruby?

Dans Ruby, il est reject!:

foo = [2, 3, 6, 7] 
foo.reject! { |x| x > 3 } 
p foo # outputs "[2, 3]" 

Y at-il un équivalent Perl?

Répondre

22
@foo = (2, 3, 6, 7); 
@foo = grep { $_ <= 3 } @foo; 
print @foo; # 23 
+0

Woah, impressionnant. Je pensais que je posais la question Perl complète d'un débutant là, mais votre réponse est votre troisième plus mise à jour. : o –

+0

@ Shtééf: les questions du débutant sont souvent des questions utiles. –

+0

@knittl Votre solution pourrait-elle être étendue pour remplacer <= avec une expression régulière? – Bnjmn

8

Comme les autres réponses suggèrent, grep est généralement tout ce que vous avez besoin.

Cependant, il est possible avec perl prototypes pour coder une fonction qui, comme Array#reject! de rubis:

  • accepte un bloc
  • peut modifier son tableau d'arguments en place

L'utilisation est:

@foo = (2, 3, 6, 7);   # Void context - modify @foo in place 
reject { $_ > 3 } @foo;   # @foo is now (2, 3) 

@foo = (2, 3, 6, 7);   # Scalar context - modify @foo in place 
$n = reject { $_ > 3 } @foo; # @foo is now (2, 3), $n is length of modified @foo 

@foo = (2, 3, 6, 7);   # Array context - return a modified copy of @foo 
@cpy = reject { $_ > 3 } @foo; # @cpy is (2, 3), @foo is (2, 3, 6, 7) 

Mise en œuvre:

sub reject(&\@) { 
    my ($block, $ary) = @_; 

    # Return a copy in an array context 
    return grep {! $block->() } @$ary if wantarray; 

    # Otherwise modify in place. Similar to, but not 
    # quite, how rb_ary_reject_bang() does it. 
    my $i = 0; 
    for (@$ary) { 
      next if $block->(); 
      ($ary->[$i], $_) = ($_, $ary->[$i]); # swap idiom to avoid copying 
      $i++;        # possibly huge scalar 
    } 
    $#$ary = $i - 1; # Shorten the input array 

    # We differ from Array#reject! in that we return the number of 
    # elements in the modified array, rather than an undef value if 
    # no rejections were made 
    return scalar(@$ary) if defined(wantarray); 
} 
+0

+1 Perle Perl. – Konerak

+0

Merci, @Konerak. Comme beaucoup d'autres, j'ai tendance à éviter les prototypes/syntaxes en bloc, mais celui-ci me semblait intuitif et peut-être utile. :) – pilcrow

+0

Liste du CPAN :: UtilsBy a une fonction extract_by() qui est comme rejeter ci-dessus, mais elle renvoie les éléments rejetés (ici appelés éléments extraits) au lieu d'une copie d'un tableau que vous avez déjà (et que vous vouliez clairement travailler de toute façon, sinon pourquoi s'embêter à le modifier). Je pense que la fonction de Leonerd est une valeur de retour plus utile. Il utilise également un \ @ proto. – masonk

Questions connexes