2010-07-08 5 views
6

J'ai un fichier CSV que j'utilise split pour analyser un tableau de N éléments, où N est un multiple de 3.En Perl, comment puis-je parcourir plusieurs éléments d'un tableau?

Est-il possible que je peux faire

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

similaire à Python?

+7

Ne pas utiliser '$ a 'et' $ b' pour les noms de variables. Ce sont des variables d'oscilloscope spécialement conçues pour être utilisées avec 'sort'. –

+0

Ce serait cool si vous pouviez le faire, cependant. –

+0

si vous êtes en dehors de la sorte, ça va. mais si c'est un one-liner que vous allez réutiliser, peut-être plus tard, alors soyez prudent, vrai. :-) – eruciform

Répondre

12

vous pouvez utiliser List::MoreUtils::natatime a partir de la documentation.

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

natatime est implémenté dans XS donc vous devriez préférer l'efficacité Juste à titre d'exemple, voici comment on pourrait mettre en œuvre trois. élément générateur de iterator en 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 * à la fois - je l'aime :-) – Mike

+0

heh drôle, ne savait pas à ce sujet. probablement une fermeture d'une ligne autour de l'épissure. :-) – eruciform

+1

@eruciform: en logique, oui, mais les fonctions dans List :: Util et List :: MoreUtils sont écrites en XS pour une vitesse maximale.C'est payant d'utiliser la fonction exacte dont vous avez besoin plutôt que d'utiliser les fonctions intégrées, lors de l'analyse d'une énorme quantité de données. – 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"; 
} 

produit:

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

cela détruit le tableau '@ z' et est probablement mieux écrit comme une boucle while –

+0

@eric: true. C'est une solution rapide. – eruciform

1

pas facilement. Vous feriez mieux de faire @d un tableau de tuples à trois éléments, en poussant les éléments sur le tableau comme une référence de tableau:

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

(Sauf que vous devez vraiment utiliser l'un des modules CSV à partir de CPAN .

+0

thx, c'est pour un hacks interne rapide, ne pensait pas que ce serait si difficile – Timmy

14

J'abordé cette question dans mon module List::Gen sur 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 

} 

Vous pouvez également importer la fonction mapn, qui est utilisé par List::Gen pour mettre en œuvre by:

use List::Gen qw/mapn/; 

mapn { 

    # do something with the slices in @_ 

} 3 => @list; 
+0

sont-ils réellement aliasés dans un "pour mon"? ou juste dans une boucle "pour"? le "mon" est censé faire une copie. Est-ce que "by" contourne cela? – eruciform

+2

la variable 'my' dans une boucle Perl foreach n'est jamais une copie, c'est toujours un alias. Un alias à portée lexicale, mais un alias tout de même. –

+3

Tout ce que je peux dire est * très gentil! * –

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"; 
} 

cette sortie:

one two three 
four five six 
seven eight nine 
Questions connexes