2010-07-08 13 views
6

N öğesinin 3 öğesinin bir katı olduğu N öğelerine ayrıştırmak için split öğelerini kullandığım bir CSV dosyası var.Perl'de, bir dizinin birden çok öğesi üzerinde nasıl yineleyebilirim?

i Python için bu

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

benzer yapabileceği bir yolu var mı?

+7

'$ a ve değişken isimler için $ b. Bunlar, 'sort' ile kullanım için özel olarak paketlenmiş kapsam değişkenleridir. –

+0

Bunu yapabilseydin harika olurdu. –

+0

türünün dışındaysanız, sorun değil. ama eğer bir tek liner ise yeniden kullanacaksın, muhtemelen daha sonra, o zaman dikkatli ol, doğru. :-) – eruciform

cevap

12

sen List::MoreUtils::natatime kullanabilirsiniz dokümanlar:.

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

natatime XS uygulanan

Eğer verimlilik için tercih edilmelidir böylece sadece gösterim amaçlı, burada bir bir üç uygulamak nasıl olduğunu. Perl eleman yineleyici jeneratör:

#!/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 * bir seferde - ben bunu seviyorum :-) – Mike

+0

heh komik, bunu bilmiyordum. Muhtemelen ekleme etrafında tek satırlık bir kapatma. :-) – eruciform

+1

@eruciform: mantık içinde, evet, ancak List :: Util ve List'deki fonksiyonlar :: MoreUtils maksimum hız için XS'de yazılmıştır.Çok fazla miktarda veriyi ayrıştırırken, yerleşik işlevleri kullanmak yerine, ihtiyacınız olan tam işlevi kullanmak gerçekten işe yarar. – 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"; 
} 

üretir: kolayca

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

idi, bu, @ @ 'dizisini yok eder ve muhtemelen bir while döngüsü olarak daha iyi yazılır –

+0

@eric: true. Bu bir quickie çözümdür. – eruciform

1

değil. Bir dizi referans olarak diziye üzerine unsurları iterek, @d üç eleman dizilerini dizisi yapma daha iyi olurdu:

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

(Eğer gerçekten CPAN CSV modüllerden birinin kullanılması gerektiğini Bunun dışında .

+0

thx, bu hızlı bir iç hack için, o kadar zor olurdu düşünmüyordu – Timmy

14

Ben CPAN Modülümde List::Gen bu sorunu ele aldı.

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 

} 

Ayrıca by uygulamak için List::Gen tarafından kullanılır mapn fonksiyonunu alabiliriz:

use List::Gen qw/mapn/; 

mapn { 

    # do something with the slices in @_ 

} 3 => @list; 
+0

aslında "benim için" takma isimler mi? ya da sadece "for" döngüsünde mi? "Benim" bir kopyasını yapmak gerekiyordu. Bu "etrafında" ile olsun? – eruciform

+2

Perl foreach döngüsündeki 'my' değişkeni asla bir kopya değildir, her zaman bir takma addır. Bir sözlüksel takma addır, ancak bir takma ad daha az değildir. –

+3

Tüm söyleyebileceğim * çok güzel! * –

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

bu çıkışlar: kullanmayın

one two three 
four five six 
seven eight nine 
İlgili konular