ハッシュの配列をdeep copyする
例えばこんなハッシュの配列の参照をコピーする場合、どうするの?
my $hashArray = [ {"aaa"=>1}, {"aaa"=>2}, {"aaa"=>3}, {"aaa"=>4} ];
先に結論
自力でやるなら、配列の中身を一個一個実体コピー
もしくは、Cloneモジュールを使う
use Clone qw(clone); # 自力の場合 my $hashArrayCopy5 = [map {{%$_}} @$hashArray]; # cloneモジュールを使う場合 my $hashArrayCopy7 = clone($hashArray);
実装
案2(shallow copy)
@$〜で、配列のリファレンスを実体化(デリファレンス)できるので、配列の実体をコピー
だけど、配列の中身は結局、ハッシュのリファレンスなので、
やっぱり、shallow copy
my @hashArrayCopy2 = @$hashArray; # @〜は、リファレンスの実体化
案3(shallow copy)
mapを使うが、この場合も結局案2と同じなのでNG
mapは、以下の 式 or ブロックの処理を
全てのリストの要素で行って、結果を配列で返す関数
- map 式, リスト
- map { ブロック }, リスト
my $hashArrayCopy3 = [map{$_}(@$hashArray)];
ちなみに、配列の配列の場合は、mapを使って、deep copy可能
my $arrayArray = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; my $arrayArrayCopy = [map[@{$_}], @$arrayArray]; $arrayArray->[0]->[0] = 999999; # 0 と表示 print $arrayArrayCopy->[0]->[0];
案4(deep copy)
配列の中身をforeachして、中身を実体でコピー
my $hashArrayCopy4 = []; foreach (@$hashArray){ my %buf = %$_; # 一度実体にコピー push(@$hashArrayCopy4, \%buf); }
案5(deep copy)
もっとスマートな方法
my $hashArrayCopy5 = [map {{%$_}} @$hashArray];
mapでは、{%$_}で、配列の参照を実体化できるが、中括弧"{"はブロック扱いになるので、以下はNG
配列の中のハッシュの全ての Key と Value を値にもった1次元配列が、$hashArrayCopy6に格納される
my $hashArrayCopy6 = [map {%$_} @$hashArray];
案6(deep copy)
Cloneモジュールを使う
use Clone qw(clone); my $hashArrayCopy7 = clone($hashArray);
ちなみに、cloneメソッドは、第二引数でdeep copyの深度を指定できる
参考
- Perlでの多次元配列の実体コピー
- Perl Lesson 7
- mapについて
- [を] ハッシュのリファレンスのリストをコピーしても
- ハッシュの配列をコピーしてもshallow copyになる例
- 多次元配列の使い方 / x.x.x.x
- 多次元配列と、そのリファレンスや無名配列の詳細な説明
その他
検証用コードはこちら(SJISです)
http://kasei-san.sakura.ne.jp/rabo/copyTest.pl
perlの配列、ハッシュのリファレンスは大体理解
他のLLと違って、わざわざ明示的にリファレンスにしたのはなんでなんだろ?
元々リファレンスが古いバージョンでは存在しなくて、全てディープコピーで多次元配列が作れなかったのを
途中のバージョンアップで、実装したのでなんかややこしくなったとかな気がする…。