2010-11-01 30 views
12

Vì vậy, điều này đã làm cho tôi đi bonkers trong nửa giờ qua. Có cách nào cho tôi để lấy một mảng mảng đến cuối của một mảng vô danh? Tôi đã thử:

(split(' ',$test_line))[1..$#_]

và tôi đã cố gắng: (split(' ',$test_line))[1..-1]

nhưng aggravatingly, không ai trong số những người làm việc. Tôi thực sự không muốn có một biến tạm thời thêm vào instantiated mảng trung gian (mà tôi không cần). Và tôi thực sự không muốn sử dụng một lớp lót xấu xí và không thể đọc được (tìm thấy một vài trong số đó trực tuyến). Có thực sự không có cách nào thẳng về phía trước để làm điều này?Có cách nào để lấy một lát đến cuối một mảng ẩn danh trong Perl không?

+2

tôi nghi ngờ câu trả lời tốt nhất sẽ là thêm biến tạm thời. Trên dòng đầu tiên của bạn, lý do '$ # _' không hoạt động là '@ _' không phải là danh sách từ biểu thức. – aschepler

Trả lời

15

Danh sách, đó là những gì bạn có trong ví dụ của bạn, không thể được cắt từ cuối. Điều này chủ yếu là vì danh sách không phải là cấu trúc dữ liệu thích hợp trong Perl, nhưng nhiều hơn một cấu trúc mà trình thông dịch sử dụng để di chuyển dữ liệu xung quanh. Vì vậy, khi biết rằng bạn chỉ có thể cắt một danh sách ngay từ đầu, các tùy chọn của bạn là đặt một biến mảng và sau đó cắt, thay đổi thuật toán của bạn để trả lại những gì bạn muốn hoặc như sau:

Nếu bạn đang gán giá trị cho một cái gì đó, bạn có thể sử dụng undef trong mỗi khe bạn không muốn:

my (undef, @list) = split ' ' => $test_line; 

Nếu bạn đăng một số mã khác, tôi có thể sửa đổi.

Hoặc, bạn có thể sử dụng một số công cụ từ lập trình hàm. Các cặp chức năng droptake có thể hữu ích để thay đổi kích thước một danh sách mà không biến thêm:

sub take { 
    my $n = shift; 
    @_[0..$n-1] 
} 
sub drop { 
    my $n = shift; 
    @_[$n..$#_] 
} 

và sau đó dụ của bạn trở nên

drop 1, split ' ' => $test_line; 

drop 1 cũng thường được gọi là tail

sub tail {drop 1, @_} 

và tất nhiên, vì tất cả những điều này quá ngắn, nếu bạn muốn nội tuyến:

sub {shift; @_}->(split ' ' => ...) 
+0

Ý tưởng của tôi nằm dọc theo các dòng: % test_hash = (split ('', $ test_line)) [1 .. $ # _]; Trong trường hợp cụ thể đó, cách tiếp cận của bạn hoạt động tốt, nhưng tôi đã hy vọng một cái gì đó chung chung hơn một chút, để khi tôi không muốn 10 món hàng đầu tiên, tôi sẽ không bị mắc kẹt khi viết ra 10 lần ... – Eli

+0

@Eli => thật đáng buồn đó không phải là một tính năng của danh sách lát trong perl5. Các giải pháp chung là một cái gì đó như 'drop' hoặc' take'. Tùy thuộc vào nội dung của bạn, bạn cũng có thể sử dụng grep để xóa các mục bạn không muốn. –

+3

Câu trả lời hay. Có * là * các giải pháp một lớp, nhưng chúng thực sự không thuộc về mã sản xuất. – tchrist

2

Tôi không tin bạn có thể chỉ định một chỉ số cho các phần tử cuối cùng của một biểu thức danh sách tùy ý, nhưng làm thế nào về:

split(' ', (split ' ', $test_line, 2)[1]) 

Bằng cách này, không có mảng vô danh ở đây (hoặc trong câu hỏi ban đầu của bạn), chỉ danh sách.

+0

Không đẹp nhất, gọi 'chia' hai lần. Bạn cũng có thể sử dụng 'split" = => ($ test_line = ~ /\s+(.*)/s && $ 1) ', nhưng tôi sẽ không ủng hộ điều đó. – tchrist

+0

Có lẽ không phải là đẹp nhất, nhưng ít nhất nó ngắn và tương đối đơn giản. – Sean

6

Khi OP nói lát, tôi nghĩ splice:

@allTheWordsExceptTheFirstTwo = splice @{[split' ', $test_line]}, 2; 
@allExceptTheFirstAndLastTwo = splice @{[split' ', $test_line]}, 2, -2; 
0

nếu bạn đang mở để tách hai lần:

my @g = (split ' ', $test_str)[1..split(' ', $test_str)]; 

hay đúng hơn (vì chia trả về số các trường được tìm thấy (nhiều hơn chỉ số của trường cuối cùng vì nó là 0-based):

my @g = (split ' ', $test_str)[1..split(' ', $test_str)-1]; 

thật không may là chúng ném một cảnh báo không được chấp nhận trong 'pragma' cảnh báo và ghi đè nội dung của @_ (trừ khi bạn đang sử dụng 5.12, sau đó bạn là tốt, nếu không đi với một biến tạm thời, nội tuyến tiểu hoặc một vòng lặp).

3

Bạn có thể sử dụng phạm vi tiêu cực trong subscript mảng để giải quyết một số bất kỳ của các yếu tố từ cuối cùng:

my $x = join ' ' => 'a' .. 'z'; 
my @x = (split ' ', $x)[-13 .. -1]; 

Tuy nhiên, điều này đòi hỏi bạn phải biết tổng số các yếu tố trong kết quả của split để loại bỏ chỉ là yếu tố đầu tiên.

Nếu điều này xảy ra chỉ trong một nơi, sử dụng một khối do nên làm việc:

my $x = join ' ', 'a' .. 'z'; 
my @x = do { my @y = (split ' ', $x); @y[1 .. $#y] }; 

Trong trường hợp của bạn, tôi sẽ yếu tố hiện toàn bộ hoạt động cho một chương trình con nếu nó là vụ phải được sử dụng thường xuyên, đi qua chuỗi hơn là kết quả của sự split đến chương trình con (có thể được khái quát hóa hơn nữa bằng cách cho phép người sử dụng để vượt qua mô hình phân chia cũng như:

my $x = join ' ', 'a' .. 'g'; 
my @x = skip_first_n_from_split(3, $x); 

print Dump \@x; 

sub skip_first_n_from_split { 
    my ($n, $x) = @_; 
    my @y = split ' ', $x; 
    return @y[$n .. $#y]; 
} 

có vui vẻ:

#!/usr/bin/perl 

use strict; use warnings; 

my $x = join ' ', 1 .. 8; 
my @skippers = map make_skipper(' ', $_), 0 .. 7; 

print "@$_\n" for map $_->($x), @skippers; 

sub make_skipper { 
    my ($pattern, $n) = @_; 

    return sub { 
     my $string = shift; 
     my $i = 0; 
     return [ grep $i++ >= $n, split $pattern, $string ]; 
    } 
} 

Output:

1 2 3 4 5 6 7 8 
2 3 4 5 6 7 8 
3 4 5 6 7 8 
4 5 6 7 8 
5 6 7 8 
6 7 8 
7 8 
8
2

này chỉ có answered 'gọn gàng' trên Perlmonks bởi BrowserUK, đây là những gì bạn muốn làm:

my @slice = sub{ @_[1..$#_] }->(split ' ', $test_line); 
Các vấn đề liên quan