2012-01-20 21 views
7

タスク:マップを使ってハッシュを構築する。ここで、キーは与えられた配列@aの要素であり、値はの最初のの要素f($ element_of_a ):FまでPerl:リストの最初の要素へのマッピング

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

すべてオーケー)()(つまり、(Fために絶対的に正しいです空のリストを返します)、その場合には、私はundefを割り当てるしたいと思います。このエラーは、次のコードで再現できます。

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

「ハッシュ割り当ての要素の奇数」のようにエラーが発生します。私は、コードを書き換えた場合、そのようなこと:

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

または

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

Perlは全く文句はありません。

それでは、どのよう私はこれを解決する必要があります - F()によって返されたリストの最初の要素を取得し、返されたリストが空であるとき?

Perlバージョンが5.12.3

ありがとう。

+3

それは空のリストを返すとき、あなたは 'undef'か、それが返されるリストのそれ以外の場合は最初の要素を供給するようにF''への呼び出しをラップします。 –

答えて

7

ちょっと遊んだことがあります。リストコンテキストで()[0]が、undefスカラーではなく空のリストとして解釈されているようです。たとえば、これは:

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

プリント0です。したがって、$_ =>()[0]は、ちょうど$_に相当します。

はそれを修正するには、スカラーコンテキストを強制するscalar機能を使用することができます。

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

をしたり、リストの最後に明示的なundefを追加することができます

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

たりすることができます関数の戻り値を真の配列(単なるリストではなく)にラップします。

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


空リストのスライスの特殊な動作が“Slices” in perldataの下で文書化されている(私は最高の、個人的に最後のオプションがあることが好きです。):

空のリストのスライスがまだあります空リスト[...]これは、空リストが返されたときに終了するループの書き込みが簡単になります:

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

私は '()[0]'がundefではなく空のリストを返す理由を説明する文書を引用して編集しました。あなたが承認していない場合は、私の編集を元に戻してください(または改善してください)。 – derobert

+0

@derobert:私は強く*承認します。どうもありがとうございました! – ruakh

+0

ここでの分析には何も問題はありませんが、それは多くの回線ノイズです。私は個人的には、 'f'がコードをより保守性のあるものにするように、端のケースを処理する方が好きです。もちろん、 'f'の定義を支配することができなければ、それはまったく別の問題です。 – Zaid

0

I二ジョナサン・レフラーの提案 - 行うための最善のことがでている場合、ルートから問題を解決することですがすべての可能性:

sub f { 

    # ... process @result 

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

空のリストの問題が回避されるため、明示的undefが必要です。

0

最初は、すべてのレプリカーに感謝します。今私は実際の仕事の実際の詳細を提供する必要があると感じています。

私は各要素のセットを含むXMLファイルがそのように見えるの解析よ:

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

私の目標は、以下のキーと値を含む要素のためのPerlのハッシュを作成することです:

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

<attr_1>要素を詳しく見てみましょう。 XML::DOM::ParserCPAN私が解析するために使用するモジュールは、クラスXML::DOM::Elementのオブジェクトを作成します。参照用に名前は$attrとしましょう。要素の名前は$attr->getNodeNameによって簡単に得たが、1が最初にすべての<attr_1>の子要素を受信する必要が<attr_1>タグで囲まれたテキストにアクセスするためのものである:含むリストを返し->getChildNodes<attr_1><attr_2>要素については

my @child_ref = $attr->getChildNodes; 

を正確に1つの参照(XML::DOM::Textクラスのオブジェクトへ)、<attr_3>の場合は空のリストを返します。 <attr_1><attr_2>の場合は$child_ref[0]->getNodeValueで値を取得する必要がありますが、<attr_3>の場合は、テキスト要素が存在しないため、undefを結果のハッシュに配置する必要があります。

ですから、f、関数の(現実の生活の中でメソッド->getChildNodes)実装は、私が書いてきたコード:-)制御することができませんでしたが(サブルーチンは要素<attr_1>ためXML::DOM::Element参照、<attr_2>のリストが提供されていることを確認し、 <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

私はあなたがこれを前に述べたとします。あなたはあなたが求める質問と同じくらい良い答えを得るだけです。この情報が以前は利用できなかったのは残念です。 – Zaid

+0

なぜですか?リストとスライスに関する多くの点を明確にする完全な答えを自分自身が持っていると思います。:-) – indexless

関連する問題