2012-01-20 33 views
7

Tác vụ: để tạo băm sử dụng bản đồ, trong đó các khóa là phần tử của mảng đã cho @a và các giá trị là các thành phần đầu tiên của danh sách được trả về bởi một số hàm f ($ element_of_a):Perl: ánh xạ thành phần tử đầu tiên của danh sách

my @a = (1, 2, 3); 
my %h = map {$_ => (f($_))[0]} @a; 

Tất cả đều ổn cho đến khi f() trả về danh sách trống (điều này hoàn toàn đúng cho f() và trong trường hợp đó tôi muốn gán undef). Lỗi có thể được sao chép bằng mã sau:

my %h = map {$_ =>()[0]} @a; 

chính lỗi đó có vẻ như "Số lượng phần tử lẻ trong phân bổ hàm băm". Khi tôi viết lại đoạn code như vậy:

my @a = (1, 2, 3); 
my $s =()[0]; 
my %h = map {$_ => $s} @a; 

hoặc

my @a = (1, 2, 3); 
my %h = map {$_ => undef} @a; 

Perl không phàn nàn gì cả.

Vậy làm cách nào để tôi giải quyết vấn đề này - lấy các phần tử đầu tiên trong danh sách được trả về bởi f(), khi danh sách trả về trống?

Phiên bản Perl là 5.12.3

Cảm ơn.

+3

Bó gọi cho 'f' để khi nó trả về một danh sách trống, bạn cung cấp 'undef' hoặc phần tử đầu tiên của danh sách nó trở lại. –

Trả lời

7

Tôi vừa mới chơi một chút và có vẻ như là ()[0], trong ngữ cảnh danh sách, được hiểu là danh sách trống thay vì là một vô hướng undef. Ví dụ: điều này:

my @arr =()[0]; 
my $size = @arr; 
print "$size\n"; 

in 0. Vì vậy, $_ =>()[0] tương đương với chỉ $_.

Để khắc phục nó, bạn có thể sử dụng scalar chức năng để buộc bối cảnh vô hướng:

my %h = map {$_ => scalar((f($_))[0])} @a; 

hoặc bạn có thể thêm một rõ ràng undef đến cuối danh sách:

my %h = map {$_ => (f($_), undef)[0]} @a; 

hoặc bạn có thể bọc giá trị trả về của hàm của bạn vào một mảng thực (thay vì chỉ là một danh sách phẳng):

my %h = map {$_ => [f($_)]->[0]} @a; 

(Tôi thích rằng tùy chọn cuối cùng tốt nhất, cá nhân.)


Các hành vi đặc biệt của một lát một danh sách trống được ghi chép lại dưới “Slices” in perldata:

Một lát một danh sách trống vẫn còn một là danh sách trống.[...] Điều này làm cho nó dễ dàng để viết vòng đó chấm dứt khi một danh sách null được trả về:

while (($home, $user) = (getpwent)[7,0]) { 
    printf "%-8s %s\n", $user, $home; 
} 
+1

Tôi đã chỉnh sửa trong một trích dẫn cho tài liệu giải thích tại sao '() [0]' trả về một danh sách trống thay vì undef. Nếu bạn không chấp thuận, vui lòng hoàn nguyên chỉnh sửa của tôi (hoặc tốt hơn, cải thiện nó). – derobert

+0

@derobert: Tôi * mạnh mẽ * phê duyệt. Cảm ơn nhiều! – ruakh

+0

Không có gì sai với các phân tích ở đây, nhưng đó là rất nhiều tiếng ồn dòng. Cá nhân tôi muốn có 'f' xử lý các trường hợp cạnh vì nó làm cho mã dễ bảo trì hơn theo cách đó. Tất nhiên, nếu không có quyền kiểm soát định nghĩa 'f', thì đó là một vấn đề khác hoàn toàn – Zaid

0

Tôi thứ hai đề nghị Jonathan Leffler của - điều tốt nhất để làm sẽ là để giải quyết vấn đề từ gốc nếu tại tất cả các khả năng:

sub f { 

    # ... process @result 

    return @result ? $result[0] : undef ; 
} 

các rõ ràng undef là cần thiết cho vấn đề danh sách trống để được phá vỡ.

0

Lúc đầu, cảm ơn nhiều đối với tất cả người chơi lại! Bây giờ tôi cảm thấy rằng tôi nên cung cấp các chi tiết thực tế của nhiệm vụ thực sự.

Tôi đang phân tích một tập tin XML chứa các thiết lập của nguyên tố từng trông như thế:

<element> 
    <attr_1>value_1</attr_1> 
    <attr_2>value_2</attr_2> 
    <attr_3></attr_3> 
</element> 

Mục tiêu của tôi là tạo ra Perl băm cho các phần tử có chứa các phím và các giá trị sau:

('attr_1' => 'value_1', 
'attr_2' => 'value_2', 
'attr_3' => undef) 

Hãy xem xét kỹ hơn phần tử <attr_1>. XML::DOM::ParserCPAN mô-đun mà tôi sử dụng để phân tích cú pháp tạo cho chúng một đối tượng của lớp XML::DOM::Element, hãy đặt tên cho số $attr để tham chiếu. Tên của nguyên tố là đã dễ dàng bằng cách $attr->getNodeName, nhưng đối với việc tiếp cận các văn bản kèm theo trong <attr_1> thẻ người ta phải nhận tất cả các yếu tố con người 's <attr_1> lúc đầu:

my @child_ref = $attr->getChildNodes; 

Đối <attr_1><attr_2> yếu tố ->getChildNodes trả về một danh sách có chứa chính xác một tham chiếu (đối tượng của XML::DOM::Text lớp), trong khi đối với <attr_3> nó sẽ trả về một danh sách trống. Đối với số <attr_1><attr_2> tôi sẽ nhận được giá trị bằng $child_ref[0]->getNodeValue, trong khi đối với <attr_3> Tôi nên đặt undef vào băm kết quả do không có phần tử văn bản ở đó.

Vì vậy, bạn thấy rằng f chức năng của (phương pháp ->getChildNodes trong cuộc sống thực) thực hiện không thể kiểm soát kết quả :-) Mã mà tôi đã viết được (các chương trình con được cung cấp với danh sách các tài liệu tham khảo cho các yếu tố XML::DOM::Element<attr_1>, <attr_2>, và <attr_3>):

sub attrs_hash(@) 
{ 
    my @keys = map {$_->getNodeName} @_; # got ('attr_1', 'attr_2', 'attr_3') 
    my @child_refs = map {[$_->getChildNodes]} @_; # got 3 refs to list of XML::DOM::Text objects 
    my @values = map {@$_ ? $_->[0]->getNodeValue : undef} @child_refs; # got ('value_1', 'value_2', undef) 

    my %hash; 
    @hash{@keys} = @values; 

    %hash; 
} 
+0

Tôi muốn bạn đã đề cập đến điều này lên phía trước. Bạn sẽ chỉ nhận được câu trả lời tốt như câu hỏi mà bạn yêu cầu. Quá tệ đến nỗi thông tin này không được cung cấp trước đây. – Zaid

+0

Tại sao? Tôi cho rằng mình có câu trả lời hoàn hảo cho phép tôi làm rõ nhiều điểm liên quan đến danh sách và lát :-) – indexless

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