2010-07-08 39 views
6

Tôi có tệp CSV mà tôi sử dụng split để phân tích thành một mảng của N mục, trong đó N là bội số của 3.Trong Perl, làm thế nào tôi có thể lặp qua nhiều phần tử của một mảng?

Có cách nào tôi có thể làm điều này

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

tương tự như Python?

+7

Không sử dụng '$ một 'và' $ b' cho các tên biến. Chúng là các biến phạm vi được đóng gói đặc biệt để sử dụng với 'sắp xếp'. –

+0

Đó sẽ là mát mẻ nếu bạn có thể làm điều đó, mặc dù. –

+0

nếu bạn đang ở bên ngoài của loại, nó là tốt. nhưng nếu đó là một lớp lót bạn sẽ tái sử dụng, có thể sắp xếp sau, thì hãy cẩn thận, đúng. :-) – eruciform

Trả lời

12

bạn có thể sử dụng List::MoreUtils::natatime Từ các tài liệu:.

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

natatime được thực hiện trong XS vì vậy bạn nên thích nó cho hiệu quả Chỉ cần cho mục đích minh hoạ, đây là cách người ta có thể thực hiện một ba. trình tạo biến tố phần tử trong 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 * tại một thời điểm - Tôi thích nó :-) – Mike

+0

heh funny, không biết về điều đó. có lẽ là một đóng cửa một dòng quanh mối nối. :-) – eruciform

+1

@eruciform: trong logic, có, nhưng các chức năng trong Danh sách :: Util và Danh sách :: MoreUtils được viết bằng XS cho tốc độ tối đa.Nó thực sự trả hết để sử dụng hàm chính xác mà bạn cần thay vì sử dụng các hàm dựng sẵn, khi phân tích một lượng lớn dữ liệu. – 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"; 
} 

sản xuất:

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

điều này phá hủy mảng '@ z' và có lẽ tốt hơn được viết dưới dạng vòng lặp while –

+0

@eric: true. đây là một giải pháp nhanh. – eruciform

1

Không dễ dàng. Bạn muốn được tốt hơn làm @d một mảng của các bộ ba yếu tố, bằng cách đẩy các yếu tố vào mảng như một tài liệu tham khảo mảng:

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

(Trừ mà bạn thực sự nên sử dụng một trong các module CSV từ CPAN .

+0

thx, nó cho một hack nội bộ nhanh chóng, didnt nghĩ rằng nó sẽ rất khó – Timmy

14

Tôi đã giải quyết vấn đề này trong mô-đun List::Gen trên 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 

} 

Bạn cũng có thể nhập khẩu các mapn chức năng, được sử dụng bởi List::Gen để thực hiện by:

use List::Gen qw/mapn/; 

mapn { 

    # do something with the slices in @_ 

} 3 => @list; 
+0

là chúng thực sự được đặt bí danh trong "đối với tôi"? hoặc chỉ trong vòng lặp "for"? "của tôi" là nghĩa vụ phải tạo một bản sao. "by" nhận được xung quanh điều này? – eruciform

+2

biến 'my' trong vòng lặp Perl foreach không bao giờ là bản sao, nó luôn là bí danh. Một bí danh lexically scoped, nhưng một bí danh không có ít hơn. –

+3

Tất cả những gì tôi có thể nói là * rất đẹp! * –

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

đầu ra này:

one two three 
four five six 
seven eight nine 
Các vấn đề liên quan