2010-07-15 15 views
5

Necesito caminar sobre una matriz y eliminar elementos condicionalmente en Perl. Sé acerca de slice, pero no estoy seguro de cómo usarlo en un contexto foreach.equivalente de Perl de `rechazo!` De Ruby?

En Ruby, no es reject!:

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

¿Hay un equivalente de Perl?

Respuesta

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

Woah, impresionante. Pensé que estaba haciendo una pregunta completa de Perl para principiantes allí, pero tu respuesta es la tercera más votada. : o –

+0

@ Shtééf: las preguntas de los principiantes suelen ser útiles. –

+0

@knittl ¿podría ampliar su solución para reemplazar el <= con una expresión regular? – Bnjmn

8

Como las otras respuestas sugieren, grep es normalmente todo lo que necesita.

Sin embargo, es posible con el Perl prototypes para codificar una función que, como el de rubí Array#reject!:

  • acepta un bloque
  • puede modificar su matriz de argumentos en su lugar

Uso es:

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

Implementación:

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 A Perl Perl. – Konerak

+0

Gracias, @Konerak. Como muchos otros, tiendo a alejarme de los prototipos/sintaxis de bloques, pero este parecía intuitivo y posiblemente útil. :) – pilcrow

+0

Lista de CPAN :: UtilsBy tiene una función extract_by() que es como rechazar arriba, pero devuelve los elementos rechazados (aquí llamados elementos extraídos) en lugar de una copia de una matriz que ya tienes (y que claramente querías trabajar de todos modos, de lo contrario, ¿por qué molestarse en modificarlo? Creo que la función de Leonerd es un valor de retorno más útil. También usa un \ @ proto. – masonk

Cuestiones relacionadas