Perlの二次元配列で悩む
Perlの機能を確認するには、デバッグモードで起動すると便利だ。LinuxでもWindowsでもコマンドラインから-de0というオプションをつけるとデバッグモードになる。
D:\WORK>perl -de0 Loading DB routines from perl5db.pl version 1.31 Editor support available. Enter h or `h h' for help, or `perldoc perldebug' for more help. main::(-e:1): 0 |
まず普通の1次元配列を作る。
DB<1> @x=qw(abc def ghi jkl) |
Xコマンドで配列の中身を表示させると、当然こうなっている。
DB<2> X x @x = ( 0 'abc' 1 'def' 2 'ghi' 3 'jkl' ) |
作った一次元配列@xを@yにコピーする。
DB<3> @y=@x |
その中身は当然同じである。
DB<4> X y @y = ( 0 'abc' 1 'def' 2 'ghi' 3 'jkl' ) |
コピーした@yの2番目(ゼロから数えて)の要素を書き換える。
DB<5> $y[2]="###" |
@xと@yを比べると、@yは変更されているが、当然@xは変更されていない。そりゃあたりまえだ。
DB<6> X x y @y = ( 0 'abc' 1 'def' 2 '###' 3 'jkl' ) @x = ( 0 'abc' 1 'def' 2 'ghi' 3 'jkl' ) |
では、これが二次元配列になるとどうか?
同じように二次元配列@xを作って@yにコピーし、@yの要素を変更してみる。
DB<7> @x=([qw(abc def ghi jkl mn)],[qw(opq rst uvw xyz)]) DB<8> X x @x = ( 0 ARRAY(0x1d54ee0) 0 'abc' 1 'def' 2 'ghi' 3 'jkl' 4 'mn' 1 ARRAY(0x1d3ab90) 0 'opq' 1 'rst' 2 'uvw' 3 'xyz' ) DB<9> @y=@x DB<10> X y DB<12> X y |
すると、@xも変わってしまっているではないか!?
DB<13> X x @x = ( 0 ARRAY(0x1d54ee0) 0 'abc' 1 'def' 2 'ghi' 3 'jkl' 4 'mn' 1 ARRAY(0x1d3ab90) 0 'opq' 1 'rst' 2 'uvw' 3 '###' ) |
なんとこれはPerlの仕様なのである。Perlの多次元配列は「参照」で実装されているので、コピーしたつもりになっていても実際には「参照のコピー」なので実体は同じものをさしており、コピーしたものを変更するとオリジナルも変更されてしまう。これは困った。
ループを回して新しい配列に代入すればもちろん実体コピーができるのだが、できればそんなことはしたくない。なにかうまい手は無いか?
二次元配列の一つ一つについてコピーすればいいのだから、map関数が使えそうな気がする。
これでどうだろう?
DB<14> @y=map @{$_},@x DB<15> X y |
ありゃりゃ、配列が一次元になってしまった。しかし方向性としては間違っていないみたいだぞ。
これでどうだ?
DB<16> @y=map @{$_},\@x DB<17> X y |
これは一見うまくいったように見えるが、表示されているアドレスを見ると@xと同じで、つまりやはり参照がコピーされていることが分かる。これだとやはりコピーを変更するとオリジナルも変わってしまう。
map関数の中で配列になるよう[]でくくってみよう。
DB<18> @y=map [@{$_}],\@x DB<19> X y |
うむぅ、配列の次元がひとつ上がってしまった。これはまずい。オリジナルを参照しているからいけないのか?
DB<20> @y=map [@{$_}],@x DB<21> X y |
おお、これは行けそうな気がする。コピーの要素を変更してみよう。
DB<22> $y[1][3]="!!!" |
さぁどうだっ!?
DB<23> X x y @y = ( 0 ARRAY(0x1d5b364) 0 'abc' 1 'def' 2 'ghi' 3 'jkl' 4 'mn' 1 ARRAY(0x1d5b2c8) 0 'opq' 1 'rst' 2 'uvw' 3 '!!!' ) @x = ( 0 ARRAY(0x1d54ee0) 0 'abc' 1 'def' 2 'ghi' 3 'jkl' 4 'mn' 1 ARRAY(0x1d3ab90) 0 'opq' 1 'rst' 2 'uvw' 3 '###' ) |
よしよし、これでいいみたいだな。
| 固定リンク
「プログラミング」カテゴリの記事
- HTMLのaudioオブジェクトで悩む(2017.07.09)
- JavaScriptで悩む(2017.04.01)
- プログラム言語「Ruby」で悩む(2016.07.03)
- 苗字の漢字で悩む(2015.09.06)
コメント