2010-10-13 9 views

Respuesta

21

Hay de rebanadas matriz:

my @slice = @array[1,42,23,0]; 

Hay una manera de generar listas entre $ x y $ y:

my @list = $x .. $y 

Hay una manera de crear listas nuevas a partir de listas:

my @new = map { $_ * 2 } @list; 

Y luego e es una manera de conseguir la longitud de una matriz:

my $len = $#array; 

Armar:

my @even_indexed_elements = @array[map { $_ * 2 } 0 .. int($#array/2)]; 

Por supuesto, no es tan bonito como la pitón equivalente, pero hace el mismo trabajo, y usted puede de Por supuesto, ponlo en una subrutina si la estás usando mucho y quieres ahorrarte algo de escritura.

También es posible que haya algo que permita escribir esto de una manera más natural en List::AllUtils.

+0

Solo tenga en cuenta que si tiene una matriz vacía, este método agregará un elemento (vacío) (de modo que la nueva matriz ya no tenga el tamaño 0). – insaner

21

Un Perl gama rebanada es la @ delante del nombre de la matriz, a continuación, la lista de índices que desee: no

@array[@indices]; 

Hay un built-in sintaxis para seleccionar múltiplos, pero no es tan difícil. Utilice grep() para producir una lista de índices que desea:

my @array = qw(zero one two three four five six); 
my @evens = @array[ grep { ! ($_ % 2) } 0 .. $#array ]; 

Si está utilizando PDL, hay un montón de buenas opciones de división.

+0

! mayor prioridad que% – ysth

+0

Sí, ese error se coló allí. Sin embargo, ya has respondido lo suficiente como para arreglar ese tipo de cosas :) –

+0

Prefiero dejarte elegir si usar() o == 0. – ysth

9

Voy a hacer esto en un proceso de dos pasos: primero generar los índices deseados, y luego utilizar una operación de división para extraerlos:

@indices = map { $_ * 2 } (0 .. int($#array/2)); 
my @extracted = @array[@indices]; 

Paso a paso, eso es:

  • generar una lista de números enteros de 0 hasta el último elemento de la matriz dividido por dos
  • multiplican cada entero por dos: ahora tenemos incluso números de cero al índice del último elemento
  • extraer aquellos elementos de la matriz original
7

Perl 6 mejorará las cosas dramáticamente, pero (¿hasta ahora?) Perl 5 tiene una capacidad de corte bastante limitada: debe especificar explícitamente los índices que desea y no puede ser de composición abierta.

Por lo que tendría que hacer:

@ar = ("zero", "one", "two", "three", "four", "five", "six"); 
print @ar[ grep $_ % 2 == 0, 0..$#ar ] 
11

He escrito el módulo List::Gen en CPAN que proporciona una forma alternativa de hacer esto:

use List::Gen qw/by/; 

my @array = qw/zero one two three four five six/; 

my @slice = map {$$_[0]} by 2 => @array; 

by particiones @array en grupos de dos elementos y devuelve una matriz de referencias de matriz. map luego obtiene esta lista, por lo que cada $_ en el mapa será una referencia de matriz. $$_[0] (que también podría escribirse $_->[0]) y luego toma el primer elemento de cada grupo creado by.

O, usando la función mapn cuales by utiliza internamente:

use List::Gen qw/mapn/; 

my @slice = mapn {$_[0]} 2 => @array; 

O, si su lista de fuentes es enorme y puede que sólo necesite ciertos elementos, puede utilizar List::Gen 's listas perezosas:

use List::Gen qw/by gen/; 

my $slicer = gen {$$_[0]} by 2 => @array; 

$slicer ahora es una lista diferida (una matriz de referencia) que generará sus sectores a pedido sin procesar nada que no haya pedido. $slicer también tiene un montón de métodos de acceso si no desea usarlo como una matriz de ref.

4

Si no se preocupan por el orden, y si los elementos con números impares de la lista son únicos, se puede convertir de forma concisa la matriz a un hash y toma el values:

@even_elements = values %{{@array}}; 
@odd_elements = keys %{{@array}}; 

(n , esta no es una respuesta seria)

+0

TMTOWTDI! * Caracteres de relleno * –

5

Una forma de hacer este más bonito es envolverlo en algo así como autobox.

por ejemplo usando autobox::Core:

use autobox::Core; 
my @ar = qw/zero one two three four five six/; 

# you could do this 
@ar->slice_while(sub{ not $_ % 2 }); 

# and this 
@ar->slice_by(2); 

# or even this 
@ar->evens; 

Así es como se puede definir estos métodos AUTOBOX:

sub autobox::Core::ARRAY::slice_while { 
    my ($self, $code) = @_; 
    my @array; 

    for (my $i = 0; $i <= $#{ $self }; $i++) { 
     local $_ = $i; 
     push @array, $self->[ $i ] if $code->(); 
    } 

    return wantarray ? @array : \@array; 
} 

sub autobox::Core::ARRAY::slice_by { 
    my ($self, $by) = @_; 
    my @array = @$self[ map { $_ * $by } 0 .. int($#{$self}/$by)]; 
    return wantarray ? @array : \@array; 
} 

sub autobox::Core::ARRAY::evens { 
    my $self = shift; 
    my @array = $self->slice_by(2); 
    return wantarray ? @array : \@array; 
} 

/I3az/

+0

Empecé a trabajar en una malla que hizo algo similar, pero luego me fui a hacer otra cosa. :) –

+0

I * oohed y aahed * durante un par de horas antes de decir * sod it * y decidí que una solución 'autobox' sería agradable de ver :) – draegtun

+1

++ para todo [' autobox'] (http: //metacpan.org/pod/autobox::Core) .. especialmente 'autobox :: Core'. –

2

Otra manera sería mediante el uso de grep:

my @array = qw(zero one two three four five six); 

print map { "$_ " } @array[grep { !($_ & 1) } 0 .. $#array]; #even 
Output:zero two four six 

print map { "$_ " } @array[grep { ($_ & 1) } 0 .. $#array]; #odd 
Output:one three five 
+0

++ para máscaras de bits :-) –

1

Si no le importa usar una característica oscura de $ | usted puede hacer esto:

{ 
    local $|; # don't mess with global $| 
    @ar = ("zero", "one", "two", "three", "four", "five", "six"); 
    $| = 0; 
    @even = grep --$|, @ar; 
    $| = 1; 
    @odd = grep --$|, @ar; 
    print "even: @even\\n"; 
    # even: zero two four six 
    print "odd: @odd\\n"; 
    # odd: one three five 
} 

o, como un revestimiento 1:

{ local $|=0; @even = grep --$|, @ar; } 

Básicamente, - $ | flip flops entre un valor de 0 y 1 (a pesar de - que normalmente disminuye un valor numérico), por lo que grep ve un valor "verdadero" en cualquier otro momento, lo que hace que devuelva cada otro elemento comenzando con el valor inicial de $ |.Tenga en cuenta que debe comenzar con 0 o 1, no con algún índice arbitrario.

+0

¿No sería más fácil hacer {my $ f = 0; @even = grep {++ $ f% 2} @ar; } –

0

Este es el código más simple sin crear matrices de índice:

sub even { my $f=0; return grep {++$f%2} @_; } 
sub odd { my $f=1; return grep {++$f%2} @_; } 
Cuestiones relacionadas