2010-07-08 11 views
6

Ho un file CSV che uso split per analizzare una serie di articoli N, dove N è un multiplo di 3.In Perl, come posso scorrere su più elementi di un array?

C'è un modo posso fare questo

foreach my ($a, $b, $c) (@d) {} 

simile a Python?

+7

Non usare '$ un 'e' $ b' per i nomi delle variabili. Loro sono variabili di scope appositamente pacchettizzate da usare con 'sort'. –

+0

Sarebbe bello se potessi farlo, comunque. –

+0

se sei fuori dall'ordinamento, va bene. ma se si tratta di un one-liner, dovrai riutilizzarlo, possibilmente in un secondo momento, quindi stai attento, vero. :-) – eruciform

risposta

12

è possibile utilizzare List::MoreUtils::natatime Dalla documentazione:.

my @x = ('a' .. 'g'); 
my $it = natatime 3, @x; 
while (my @vals = $it->()) { 
    print "@vals\n"; 
} 

natatime è implementato in XS così si dovrebbe preferire per l'efficienza solo a scopo illustrativo, ecco come si potrebbe implementare un tre. elemento generatore di iteratore in Perl:

#!/usr/bin/perl 

use strict; use warnings; 

my @v = ('a' .. 'z'); 

my $it = make_3it(\@v); 

while (my @tuple = $it->()) { 
    print "@tuple\n"; 
} 

sub make_3it { 
    my ($arr) = @_; 
    { 
     my $lower = 0; 
     return sub { 
      return unless $lower < @$arr; 
      my $upper = $lower + 2; 
      @$arr > $upper or $upper = $#$arr; 
      my @ret = @$arr[$lower .. $upper]; 
      $lower = $upper + 1; 
      return @ret; 
     } 
    } 
} 
+0

* n * alla volta - Mi piace :-) – Mike

+0

heh divertente, non sapevo di quello. probabilmente una chiusura a una linea attorno alla giunzione. :-) – eruciform

+1

@eruciform: in logica, sì, ma le funzioni in List :: Util e List :: MoreUtils sono scritte in XS per la massima velocità.È davvero vantaggioso utilizzare la funzione esatta di cui hai bisogno, piuttosto che utilizzare le funzioni integrate, quando si analizza un'enorme quantità di dati. – Ether

4
@z=(1,2,3,4,5,6,7,8,9,0); 

for(@tuple=splice(@z,0,3); @tuple; @tuple=splice(@z,0,3)) 
{ 
    print "$tuple[0] $tuple[1] $tuple[2]\n"; 
} 

produce:

1 2 3 
4 5 6 
7 8 9 
0 
+1

questo distrugge l'array '@ z' e probabilmente è meglio scritto come un ciclo while –

+0

@eric: true. questa è una soluzione rapida. – eruciform

1
Non

facilmente. Si sarebbe meglio fare @d una serie di tuple di tre elementi, spingendo gli elementi sulla matrice come un riferimento ad array:

foreach my $line (<>) 
    push @d, [ split /,/, $line ]; 

(tranne che si dovrebbe davvero utilizzare uno dei moduli CSV da CPAN .

+0

thx, è per un rapido hacking interno, non pensavo sarebbe stato così difficile – Timmy

14

ho affrontato la questione nel mio modulo List::Gen su CPAN.

use List::Gen qw/by/; 

for my $items (by 3 => @list) { 

    # do something with @$items which will contain 3 element slices of @list 

    # unlike natatime or other common solutions, the elements in @$items are 
    # aliased to @list, just like in a normal foreach loop 

} 

Si potrebbe anche importare la funzione mapn, che viene utilizzato da List::Gen per implementare by:

use List::Gen qw/mapn/; 

mapn { 

    # do something with the slices in @_ 

} 3 => @list; 
+0

sono effettivamente alias in un "per il mio"? o solo in un ciclo "for"? il "mio" dovrebbe fare una copia. fa "by" aggirare questo? – eruciform

+2

la variabile 'my' in un ciclo Foreach foreach non è mai una copia, è sempre un alias. Un alias lessicalmente comprensibile, ma un alias nondimeno. –

+3

Tutto quello che posso dire è * molto bello! * –

4
my @list = (qw(one two three four five six seven eight nine)); 

while (my ($m, $n, $o) = splice (@list,0,3)) { 
    print "$m $n $o\n"; 
} 

queste uscite:

one two three 
four five six 
seven eight nine 
Problemi correlati