Perlのmapについて
Perl入学式in大阪第5回「map関数」についての補足事項です。
map関数を使えば、与えられた配列のデータをすべて2倍にする処理、与えられた配列のデータの中のスペースを全て取り除く処理、などが書けます。 #Perl入学式
— tomcha (@tomcha_) January 17, 2015
注意点は、mapもgrepも、元のデータを書き換えるのではなく、元のデータから抽出・置き換えをした新たな配列データを返す、という点です。 #Perl入学式
— tomcha (@tomcha_) January 17, 2015
講義中に自分でテストコードを書いて試してからツイートをしたのですが、mapの話が懇親会で話題にあがり、@azumakuniyukiさんより、「mapは破壊的関数ちゃうのん?」と指摘があり、 その後にもう少し突っ込んでサンプルコードを試したところ、ツイートの「mapは、元のデータを書き換えるのではなく」は誤っていました。すみませんでした。
結論
map関数は「破壊的関数」であり、元の配列のデータは更新(上書き)されるケースがあります。
更新されるケースとは?
こういう事はコードを書いて実験するのが一番です。
4つのパターンのmap関数使用例を書いてみました。
講義中にササッと書いてテストしたのはコード14行目の"a"のパターンです。
この使い方だと、確かに元の配列@aの中身は変更されず、別の配列@bに代入された結果だけが'.bak'を付加されているので、一見、「map関数は元の配列データを更新しない」様に見えます。
しかし、本当にそうだったのでしょうか? コード17行目"c"のパターン、コード18行目"d"のパターンともに元の配列@aaのデータは正規表現の条件式に当てはまるデータは".bak"を付加され、データが更新されていました。
"c"、"d"は正規表現の置換のコードです。$の値が置換されますね。それに対して"a"のパターンは$の値を”参照”はしているものの、代入する表現は含まれていません。代入をするパターンとして、コード15行目を試してみると、何と@aは元の配列のデータが更新されました。
この実験コードのテストから、$_は元の配列の個々のデータを参照しているので、当然書き換えれば元の配列のデータは書き換わることが分かります。ということは、「mapは破壊的関数で元のデータを更新する」という事ですね。
ただし、パターン"a"の様な、配列のデータを参照にとどめている場合は自動で更新されません。
なので、「mapは破壊的関数で元のデータを更新するが、中の式によって更新しないケースもあるので、ケースに応じて意図した通りに元の配列が更新されるか(又は更新されないか)を注意する必要がある」という事ですね。
結論その2
という事で、この話題も懇親会で色々講義の内容をワイワイ話した結果得られた知見でした。
懇親会、大事ですね。ざっくばらんに質問したり、話をしたりできる場ですので、講義だけでは聞けなかった事や、間違って解釈してしまっていた事が分かる場でもあります。また、サポーター陣も完全では無いので、今回のように間違いを発見できる場でもありました。
懇親会、大事。