2

%hash にキーが存在する場合、%hash1 にキーと値のペアを配置しようとしました %hash にエントリがない要素が配列に 1 つあります。例: @array = (1,2,3,4,5); #%hash にキー 1 のハッシュ エントリがありません

だから私は map が仕事をするだろうと思ったし、新しいハッシュ、つまり %hash1 で 4 つのキーを取得しますが、5 つのキーを取得します。同時に foreach を試してみましたが、うまくいきました。map を使って foreach を置き換えられるのではないかと妄想していたのですが、今回の件で考えさせられました。私の論理がどこで間違っているのか、誰か説明できますか?

#Method 1. Comment it while using Method 2
%hash1 = map { $_=>$hash{$_}  if(exists $hash{$_}) } @array;

# Method 2. Comment whole loop while using method 1
foreach (@array){
    $hash1{$_} = $hash{$_} if(exists $hash{$_});
}
4

4 に答える 4

9

問題は、map式がundefの最初の要素に対して false の値を返すこと@arrayです。そして、それはハッシュキーとして使用されているため、空の文字列に文字列化されます。 (コメントで、ボロディンはこの説明が間違っていると指摘しています。実際、空の文字列はexists、キーが「1」のときに返される偽の値に由来します)

stricta) 有効にしwarnings、b)Data::Dumper作成したハッシュを表示するために使用すると、何が行われているかをよりよく理解できるかもしれません。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;

my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );

my %hash1 = map { $_=>$hash{$_}  if(exists $hash{$_}) } @array;

say Dumper \%hash1;

これは、次のようなハッシュになることを示しています。

$ ./hash 

Odd number of elements in hash assignment at ./hash line 12.
$VAR1 = {
          '' => 2,
          'three' => 4,
          'five' => undef,
          'two' => 3,
          'four' => 5
        };

奇数の要素を持つリストを生成しています。そして、それはハッピーハッシュにはなりません。

ハッシュを作成するときは、要素の数が偶数であることを確認する必要があります。したがって、使用している場合はmap、反復ごとにゼロまたは 2 つの要素を返す必要があります。したがって、次のようなものが必要です。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;

my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );

my %hash1 = map { exists $hash{$_} ? ($_ => $hash{$_}) : () } @array;

say Dumper \%hash1;

最初のハッシュでキーが見つからない場合、明示的に空のリストを返すことに注意してください。

$ ./hash2
$VAR1 = {
          '4' => 'four',
          '3' => 'three',
          '2' => 'two',
          '5' => 'five'
        };
于 2012-07-13T09:44:44.180 に答える
4

mapは常に、コード ブロックに入力したものを返します。したがって、戻り値は

%hash1 = map { $_=>$hash{$_}  if(exists $hash{$_}) } @array;

存在する$_=>$hash{$_}場合と$hash{$_}存在""しない場合になります。

あなたがおそらく書きたかったこと:

my %hash1 = map { exists($hash{$_}) ? ($_ => $hash{$_}) : () }
于 2012-07-13T09:45:02.173 に答える
3

呼び出しのブロックはmap、提供されたリスト内のすべての値について評価され、ブロックによって返される値は、最後に評価された式の値です。

あなたのmap声明

my %hash1 = map { $_ => $hash{$_}  if (exists $hash{$_}) } @array

と同等です

my %hash1 = map {
  if (exists $hash{$_}) {
    $_ => $hash{$_}
  }
} @array

したがって、最初に式exists $hash{$_}が評価されます。次に、それが真である場合、$_ => $hash{$_}が評価されます。

したがって、最後に評価された式は$_ => $hash{$_}、テストが成功した場合に必要なものですが、テストが失敗した場合、ブロックはの値を返しますexists $hash{$_}

existsはtrueまたはfalseのいずれ1かを返すため、キーとして表示されない要素は、返されるリスト内の単一の空の文字列になります。""@array%hashmap

map配列に割り当てると、結果を確認しやすくなります。そうすれば、警告やハッシュ値Odd number of elements in hash assignmentの自動割り当てを回避できます。undef

代わりに書く場合

my @arr = map { $_ => $hash{$_}  if (exists $hash{X}) } @array;

(つまり、テストは常に失敗します)結果はの結果と同じです

my @arr = map { exists $hash{X} } @array;

あるいは単に

("", "", "", "")

を使用してこれを記述する方法mapは、条件が失敗した場合に空のリストを返すように条件演算子を使用することです。

my %hash1 = map { exists $hash{$_} ? ( $_ => $hash{$_} ) : () } @array

foreachループが機能する理由の説明は必要ないと思いますか?

returnサブルーチンで許可されているのと同じように、すべてのブロック内で有効である場合があると思います。wantarrayここではすでに有効であり、ブロックが一般に終了して明示的な値を返すことを禁止するのは特定の制限です。

于 2012-07-13T10:19:34.887 に答える
2
my %hash1 = map { ( $_ => $hash{$_} ) if exists($hash{$_}) } @array;

と同じことです

my %hash1 = map { exists($hash{$_}) and ( $_ => $hash{$_} ) } @array;

exists($hash{$_})が false の場合に何が起こるかを考えてみましょう。単一の値 (dualvar(0,"")別名「偽の値」) が返されるべきでない場合に返されます。existsが falseの場合に空のリストを返すように式を変更できます。

my %hash1 = map { exists($hash{$_}) ? ( $_ => $hash{$_} ) : () } @array;

または、フィルタリングをmap

my %hash1 = map { $_ => $hash{$_} } grep { exists($hash{$_}) } @array;
于 2012-07-13T18:07:43.127 に答える