1. ホーム
  2. perl

[解決済み] Perlのハッシュのキーを反復処理する最も安全な方法は何ですか?

2022-10-22 08:02:30

質問

Perl のハッシュにたくさんの (キー, 値) のペアがある場合、すべてのキーを反復処理するにはどのような方法が望ましいでしょうか。 私は each を使用すると、何らかの形で意図しない副作用があると聞いたことがあります。 では、それは本当なのでしょうか。また、以下の2つの方法のうち1つが最適なのでしょうか、それとももっと良い方法があるのでしょうか。

# Method 1
while (my ($key, $value) = each(%hash)) {
    # Something
}

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}

どのように解決するのですか?

経験則では、ニーズに最も適した関数を使用することです。

もしあなたがキーが欲しいだけで、決して を読む を読む予定がない場合は、keys() を使用します。

foreach my $key (keys %hash) { ... }

値だけ欲しい場合は、values()を使ってください。

foreach my $val (values %hash) { ... }

キーが必要な場合 が必要な場合は、each()を使用します。

keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }

ハッシュのキーを何らかの方法で変更する予定がある場合 を除いて を除いて、何らかの方法でハッシュのキーを変更するつもりなら、 each() を使ってはいけません。 たとえば、2 倍の値を持つ大文字のキーの新しいセットを作成するこのコードは、keys() を使用しても問題なく動作します。

%h = (a => 1, b => 2);

foreach my $k (keys %h)
{
  $h{uc $k} = $h{$k} * 2;
}

期待される結果のハッシュを生成します。

(a => 1, A => 2, b => 2, B => 4)

しかし、each()を使って同じことをするのは

%h = (a => 1, b => 2);

keys %h;
while(my($k, $v) = each %h)
{
  $h{uc $k} = $h{$k} * 2; # BAD IDEA!
}

は、予測困難な方法で不正確な結果を生成します。 例えば

(a => 1, A => 2, b => 2, B => 8)

ただし、これは安全です。

keys %h;
while(my($k, $v) = each %h)
{
  if(...)
  {
    delete $h{$k}; # This is safe
  }
}

これら全ては、perlのドキュメントに記載されています。

% perldoc -f keys
% perldoc -f each