2010-10-13 6 views

risposta

21

C'è fette di matrice:

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

C'è un modo per generare liste tra $ xe $ y:

my @list = $x .. $y 

C'è un modo per costruire nuovi elenchi dagli elenchi:

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

E lì e 'un modo per ottenere la lunghezza di un array:

my $len = $#array; 

mettere insieme:

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

Certo, non è così bello come il pitone equivalente, ma fa lo stesso lavoro, e si può di Naturalmente mettilo in una subroutine se lo stai usando molto e vuoi salvarti da una scrittura.

Inoltre, è possibile che lo si possa scrivere in modo più naturale in List::AllUtils.

+0

Tieni presente che se hai un array vuoto, questo metodo aggiungerà un elemento (vuoto) ad esso (in modo che il nuovo array non sia più di dimensione 0). – insaner

21

Un Perl fetta array è la @ davanti al nome della matrice, quindi l'elenco degli indici che si desidera: non

@array[@indices]; 

C'è un built-in sintassi per selezionare multipli, ma non è così difficile. Usare grep() per produrre un elenco di indici che si desidera:

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

Se si utilizza PDL, ci sono un sacco di belle opzioni di taglio.

+0

! precedenza più alta di% – ysth

+0

Sì, quell'errore è arrivato lì. Tuttavia, sei abbastanza repped per sistemare questo genere di cose :) –

+0

Preferisco invece scegliere se usare() o == 0. – ysth

9

Farò questo in un processo in due fasi: in primo luogo generare gli indici desiderati, e quindi utilizzare un'operazione di affettamento per estrarli:

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

Step-by-step, quello è:

  • generare un elenco di numeri interi da 0 fino all'ultimo elemento dell'array diviso due
  • moltiplicare ogni numero intero da due: ora abbiamo anche i numeri da zero a l'indice dell'ultimo elemento
  • estrarre gli elementi dalla matrice originale
7

Perl 6 migliorerà notevolmente le cose, ma (finora?) Perl 5 ha una capacità di taglio piuttosto limitata: devi specificare in modo esplicito gli indici che desideri e non può essere aperto.

Quindi dovreste fare:

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

Ho scritto il modulo List::Gen su CPAN che fornisce un modo alternativo per fare questo:

use List::Gen qw/by/; 

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

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

by partizioni @array in gruppi di due elementi e restituisce una matrice di riferimenti di matrice. map ottiene questo elenco, quindi ogni $_ nella mappa sarà un riferimento di matrice. $$_[0] (che potrebbe anche essere scritto $_->[0]) quindi acquisisce il primo elemento di ogni gruppo creato da by.

Oppure, usando la funzione mapn che by usa internamente:

use List::Gen qw/mapn/; 

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

Oppure, se l'elenco sorgente è enorme e si può solo bisogno di alcuni elementi, è possibile utilizzare List::Gen s' liste pigri:

use List::Gen qw/by gen/; 

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

$slicer è ora una lista pigra (un array ref) che genererà le sue fette su richiesta senza elaborare tutto ciò che non hai richiesto. $slicer ha anche una serie di metodi di accesso se non si desidera utilizzarlo come riferimento dell'array.

4

Se non vi interessa circa l'ordine, e se gli elementi dispari della lista sono unici, si può sinteticamente Converte l'array in un hash e prendere il values:

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

(No , questa non è una risposta seria)

+0

TMTOWTDI! * caratteri di riempimento * –

5

Un modo per rendere questo più carino è quello di avvolgere in qualcosa come autobox.

ad esempio utilizzando 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; 

In questo modo è possibile definire questi metodi 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

Ho iniziato a lavorare su un unmesh che ha fatto qualcosa di simile, ma poi sono andato a fare qualcos'altro. :) –

+0

I * oohed e aahed * per un paio d'ore prima ho detto * sod * e ho deciso che una soluzione 'autobox' sarebbe bella da vedere :) – draegtun

+1

++ per tutte le cose [' autobox'] (http: //metacpan.org/pod/autobox::Core) .. specialmente 'autobox :: Core'. –

2

Un altro modo sarebbe utilizzando 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

++ per maschere di bit :-) –

1

Se non ti dispiace usare una funzione oscura di $ | si può fare questo:

{ 
    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, come 1 fodera:

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

In sostanza, - $ | flip flop tra un valore 0 e 1 (nonostante il valore - che normalmente decrementa un valore numerico), quindi grep vede un valore "true" ogni volta, causando così il ritorno di ogni altro elemento a partire dal valore iniziale di $ |.Nota che devi iniziare con 0 o 1, non con un indice arbitrario.

+0

Non sarebbe più facile fare {my $ f = 0; @even = grep {++ $ f% 2} @ar; } –

0

Ecco il codice più semplice senza creare array Indice:

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