2010-03-28 16 views
10

Tôi có cấu trúc dữ liệu là một băm có chứa một mảng băm. Tôi muốn đạt được trong đó và kéo ra băm đầu tiên phù hợp với một giá trị tôi đang tìm kiếm. Tôi cố gắng này:Tại sao sự dịch chuyển của Perl phàn nàn 'Loại arg 1 để dịch chuyển phải là mảng (không phải là biến lặp grep).'?

my $result = shift grep {$_->{name} eq 'foo'} @{$hash_ref->{list}}; 

Nhưng điều đó mang lại cho tôi lỗi này: Type of arg 1 to shift must be array (not grep iterator). Tôi đã đọc lại perldoc cho grep và tôi nghĩ rằng những gì tôi đang làm có ý nghĩa. grep trả về một danh sách, đúng không? Nó có trong ngữ cảnh sai không?

Tôi sẽ sử dụng biến tạm thời cho bây giờ, nhưng tôi muốn tìm hiểu lý do tại sao điều này không hiệu quả.

Trả lời

18

A list isn't an array.

my ($result) = grep {$_->{name} eq 'foo'} @{$hash_ref->{list}}; 

… nên thực hiện công việc. Quay trở lại từ grep trong ngữ cảnh danh sách, nhưng không gán bất kỳ giá trị nào khác với giá trị đầu tiên.

+5

Tôi nghĩ tôi sẽ viết 'Danh sách không phải là mảng' 100 lần trên bảng trắng của tôi. Cảm ơn. – wes

+0

Có một câu trả lời tốt hơn cho Câu hỏi thường gặp đó ngay bây giờ: http://www.effectiveperlprogramming.com/blog/39 –

+0

@brian d foy - Khi nào Câu hỏi thường gặp được cập nhật? (tức là chúng ta sẽ thấy nó trong một bản phát hành điểm của Perl 5 phiên bản 10, hoặc nó sẽ có trong phiên bản 12?) – Quentin

17

Tôi nghĩ rằng một cách tốt hơn để viết những dòng này sẽ là:

use List::Util qw/first/; 

my $result = first { $_->{name} eq 'foo' } @{ $hash_ref->{list} }; 

Không chỉ nó sẽ được rõ ràng hơn những gì bạn đang cố gắng để làm, nó cũng sẽ nhanh hơn bởi vì nó sẽ ngăn chặn grepping mảng của bạn một khi nó đã tìm thấy phần tử phù hợp.

2

Một cách khác để làm điều đó:

my $result = (grep {$_->{name} eq 'foo'} @{$hash_ref->{list}})[0]; 

Lưu ý rằng curlies xung quanh đối số đầu tiên để grep là không cần thiết trong trường hợp này, vì vậy bạn có thể tránh được thiết lập ngăn chặn và teardown chi phí với

my $result = (grep $_->{name} eq 'foo', @{$hash_ref->{list}})[0]; 

“List value constructors” in perldata tài liệu subscripting của danh sách:

A list value may also be subscripted like a normal array. You must put the list in parentheses to avoid ambiguity. For example:

# Stat returns list value. 
$time = (stat($file))[8]; 

# SYNTAX ERROR HERE. 
$time = stat($file)[8]; # OOPS, FORGOT PARENTHESES 

# Find a hex digit. 
$hexdigit = ('a','b','c','d','e','f')[$digit-10]; 

# A "reverse comma operator". 
return (pop(@foo),pop(@foo))[0]; 

Khi tôi nhớ lại, chúng tôi có tính năng này khi Randal Schwartz đùa giỡn gợi ý, và Chip Salzenberg —một máy vá trong những ngày đó — đã thực hiện nó vào tối hôm đó.

Cập nhật: Một chút tìm kiếm cho thấy tính năng tôi nghĩ đến là $coderef->(@args). Thông báo cam kết thậm chí ghi lại cuộc trò chuyện!

Các vấn đề liên quan