7

タスク: マップを使用してハッシュを作成します。ここで、キーは指定された配列 @a の要素であり、値は関数 f($element_of_a) によって返されるリストの最初の要素です。

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

f() が空のリストを返すまでは問題ありません (これは 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 です

ありがとう。

4

3 に答える 3

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;

(個人的には、最後のオプションが一番好きです。)


空のリストのスライスの特別な動作は、次の「スライス」にperldata記載されています。

空のリストのスライスはまだ空のリストです。[…]これにより、nullリストが返されたときに終了するループを簡単に作成できます。

while ( ($home, $user) = (getpwent)[7,0]) {
    printf "%-8s %s\n", $user, $home;
}
于 2012-01-20T18:16:34.143 に答える
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::Parser CPAN解析に使用するモジュールは、クラスのオブジェクトを作成します。参照用XML::DOM::Elementの名前を付けましょう$attr。要素の名前は で簡単に取得できますが、タグ$attr->getNodeNameで囲まれたテキストにアクセスするには、最初に のすべての子要素を受け取る必要があります。<attr_1><attr_1>

my @child_ref = $attr->getChildNodes;

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

したがって、f関数 (->getChildNodes実際のメソッド) の実装を制御できなかったことがわかります:-) 私が書いた結果のコードは次のとおりです (サブルーチンにはXML::DOM::Element、要素<attr_1><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;
}
于 2012-01-21T18:48:21.353 に答える
0

私はジョナサン・レフラーの提案に賛成です - 最善の方法は、可能であれば根本から問題を解決することです:

sub f {

    # ... process @result

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

undef空のリストの問題を回避するには、明示的に指定する必要があります。

于 2012-01-20T21:55:14.430 に答える