Programmingバックエンド開発者

Perlにおけるリスト操作のmapとgrepはどのように機能しますか?それらの違いは何ですか、そして使用時に予期しない副作用を避けるにはどうすればよいですか?

Hintsage AIアシスタントで面接を突破

回答

mapgrepは、配列を操作するためのPerlの強力な関数です:

  • mapは、リストの各要素に式を適用し、結果を含む新しいリストを返します。
  • grepは、式が真の値を返すリストの要素を返します(フィルタリング)。

使用例:

my @nums = (1, 2, 3, 4, 5, 6); my @squared = map { $_ * $_ } @nums; # (1, 4, 9, 16, 25, 36) my @even = grep { $_ % 2 == 0 } @nums; # (2, 4, 6)

重要

  • スコープ: mapgrepのブロック内で、変数$_はデフォルトで現在の要素を含みます。$_を修正すると、配列が参照渡しされている場合やforeachで別名が使用されている場合に、元の配列の要素自体が変更されることがあります。
  • 返り値: mapは常にリストを返し、grepは元のリストのサブセットを返します。

トリック質問

質問: 次のコードは何をし、なぜですか?

my @nums = (1..5); my @result = map { $_++ } @nums; print "@nums ";

回答: このコードは元の配列@numsを変更しません。演算子$_++はブロック内の変数の値を増やしますが、元の配列にはその変更は保存されません。なぜなら、mapは変更された値を返しますが、元の配列は影響を受けないからです(foreachで別名が使用されている場合を除く)。

例:

my @nums = (1..5); my @result = map { $_++ } @nums; # @resultは(1,2,3,4,5)となり、@numsは変わりません print "@nums "; # 出力: 1 2 3 4 5

このテーマの微妙な点を知らないことによる実際のエラーの例


ストーリー あるプロジェクトで、開発者は map { $_++ } @array の後に、配列 @array が変更されると期待していました。その結果、プログラムは古い値のまま動作し、データの集計時に不正確な計算を引き起こしました。


ストーリー レポートシステムでは、配列を grep でフィルタリングする際、ブロック内で間違って $result = $_ という代入文を使用してしまい、すべての要素が同じ変数に上書きされ、データソースが失われました。これによりデバッグが難しくなり、レポートに損失をもたらしました。


ストーリー 統合スクリプト内で、ネストされた map を使用し、内部コンテキストも共通の変数 $_ で動作することを忘れたため、要素の変更時に予測不可能な動作が発生しました。内部の map が結果の配列に値を上書きしました。